Compare commits

..

1 Commits

Author SHA1 Message Date
Christopher Haster
52df70c669 Fixed name ordering when names only differ in length
Wild this hasn't been caught until now.

Because the exact ordering of the comparison in lfs_bd_cmp is a bit
ambiguous, lfs_dir_find_match returned the wrong result when filenames
were equal, and only differed in length.

For example:

  - cmp("a", "aa") should be LFS_CMP_LT
  - cmp("aaa", "aa") should be LFS_CMP_GT

We're quite lucky that none of the littlefs internals currently depend
on the sorted order, otherwise we'd probably be stuck with this weird
ordering for backwards compatibility reasons...

Fixed, and added some test cases over directory ordering to prevent
regression in the future.

Found by andriyndev
2024-01-17 14:38:04 -06:00
60 changed files with 13901 additions and 22407 deletions

View File

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

View File

@@ -11,7 +11,7 @@ defaults:
jobs:
release:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
# need to manually check for a couple things
# - tests passed?
@@ -20,7 +20,7 @@ jobs:
github.event.workflow_run.head_sha == github.sha}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
ref: ${{github.event.workflow_run.head_sha}}
# need workflow access since we push branches
@@ -30,72 +30,69 @@ jobs:
fetch-depth: 0
# try to get results from tests
- uses: actions/download-artifact@v4
- uses: dawidd6/action-download-artifact@v2
continue-on-error: true
with:
github-token: ${{secrets.GITHUB_TOKEN}}
run-id: ${{github.event.workflow_run.id}}
pattern: '{sizes,sizes-*}'
merge-multiple: true
workflow: ${{github.event.workflow_run.name}}
run_id: ${{github.event.workflow_run.id}}
name: sizes
path: sizes
- uses: actions/download-artifact@v4
- uses: dawidd6/action-download-artifact@v2
continue-on-error: true
with:
github-token: ${{secrets.GITHUB_TOKEN}}
run-id: ${{github.event.workflow_run.id}}
pattern: '{cov,cov-*}'
merge-multiple: true
workflow: ${{github.event.workflow_run.name}}
run_id: ${{github.event.workflow_run.id}}
name: cov
path: cov
- uses: actions/download-artifact@v4
- uses: dawidd6/action-download-artifact@v2
continue-on-error: true
with:
github-token: ${{secrets.GITHUB_TOKEN}}
run-id: ${{github.event.workflow_run.id}}
pattern: '{bench,bench-*}'
merge-multiple: true
workflow: ${{github.event.workflow_run.name}}
run_id: ${{github.event.workflow_run.id}}
name: bench
path: bench
- name: find-version
run: |
# rip version from lfs2.h
LFS2_VERSION="$(grep -o '^#define LFS2_VERSION .*$' lfs2.h \
# rip version from lfs.h
LFS_VERSION="$(grep -o '^#define LFS_VERSION .*$' lfs.h \
| awk '{print $3}')"
LFS2_VERSION_MAJOR="$((0xffff & ($LFS2_VERSION >> 16)))"
LFS2_VERSION_MINOR="$((0xffff & ($LFS2_VERSION >> 0)))"
LFS_VERSION_MAJOR="$((0xffff & ($LFS_VERSION >> 16)))"
LFS_VERSION_MINOR="$((0xffff & ($LFS_VERSION >> 0)))"
# find a new patch version based on what we find in our tags
LFS2_VERSION_PATCH="$( \
LFS_VERSION_PATCH="$( \
( git describe --tags --abbrev=0 \
--match="v$LFS2_VERSION_MAJOR.$LFS2_VERSION_MINOR.*" \
--match="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.*" \
|| echo 'v0.0.-1' ) \
| awk -F '.' '{print $3+1}')"
# found new version
LFS2_VERSION="v$LFS2_VERSION_MAJOR`
`.$LFS2_VERSION_MINOR`
`.$LFS2_VERSION_PATCH"
echo "LFS2_VERSION=$LFS2_VERSION"
echo "LFS2_VERSION=$LFS2_VERSION" >> $GITHUB_ENV
echo "LFS2_VERSION_MAJOR=$LFS2_VERSION_MAJOR" >> $GITHUB_ENV
echo "LFS2_VERSION_MINOR=$LFS2_VERSION_MINOR" >> $GITHUB_ENV
echo "LFS2_VERSION_PATCH=$LFS2_VERSION_PATCH" >> $GITHUB_ENV
LFS_VERSION="v$LFS_VERSION_MAJOR`
`.$LFS_VERSION_MINOR`
`.$LFS_VERSION_PATCH"
echo "LFS_VERSION=$LFS_VERSION"
echo "LFS_VERSION=$LFS_VERSION" >> $GITHUB_ENV
echo "LFS_VERSION_MAJOR=$LFS_VERSION_MAJOR" >> $GITHUB_ENV
echo "LFS_VERSION_MINOR=$LFS_VERSION_MINOR" >> $GITHUB_ENV
echo "LFS_VERSION_PATCH=$LFS_VERSION_PATCH" >> $GITHUB_ENV
# try to find previous version?
- name: find-prev-version
continue-on-error: true
run: |
LFS2_PREV_VERSION="$( \
LFS_PREV_VERSION="$( \
git describe --tags --abbrev=0 --match 'v*' \
|| true)"
echo "LFS2_PREV_VERSION=$LFS2_PREV_VERSION"
echo "LFS2_PREV_VERSION=$LFS2_PREV_VERSION" >> $GITHUB_ENV
echo "LFS_PREV_VERSION=$LFS_PREV_VERSION"
echo "LFS_PREV_VERSION=$LFS_PREV_VERSION" >> $GITHUB_ENV
# try to find results from tests
- name: create-table
run: |
# previous results to compare against?
[ -n "$LFS2_PREV_VERSION" ] && curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/$LFS2_PREV_VERSION`
[ -n "$LFS_PREV_VERSION" ] && curl -sS \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/$LFS_PREV_VERSION`
`?per_page=100" \
| jq -re 'select(.sha != env.GITHUB_SHA) | .statuses[]' \
>> prev-status.json \
@@ -205,10 +202,10 @@ jobs:
# find changes from history
- name: create-changes
run: |
[ -n "$LFS2_PREV_VERSION" ] || exit 0
[ -n "$LFS_PREV_VERSION" ] || exit 0
# use explicit link to github commit so that release notes can
# be copied elsewhere
git log "$LFS2_PREV_VERSION.." \
git log "$LFS_PREV_VERSION.." \
--grep='^Merge' --invert-grep \
--format="format:[\`%h\`](`
`https://github.com/$GITHUB_REPOSITORY/commit/%h) %s" \
@@ -220,25 +217,25 @@ jobs:
- name: create-major-branches
run: |
# create major branch
git branch "v$LFS2_VERSION_MAJOR" HEAD
git branch "v$LFS_VERSION_MAJOR" HEAD
# create major prefix branch
git config user.name ${{secrets.BOT_USER}}
git config user.email ${{secrets.BOT_EMAIL}}
git fetch "https://github.com/$GITHUB_REPOSITORY.git" \
"v$LFS2_VERSION_MAJOR-prefix" || true
./scripts/changeprefix.py --git "lfs2" "lfs2$LFS2_VERSION_MAJOR"
git branch "v$LFS2_VERSION_MAJOR-prefix" $( \
"v$LFS_VERSION_MAJOR-prefix" || true
./scripts/changeprefix.py --git "lfs" "lfs$LFS_VERSION_MAJOR"
git branch "v$LFS_VERSION_MAJOR-prefix" $( \
git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \
-m "Generated v$LFS2_VERSION_MAJOR prefixes")
-m "Generated v$LFS_VERSION_MAJOR prefixes")
git reset --hard
# push!
git push --atomic origin \
"v$LFS2_VERSION_MAJOR" \
"v$LFS2_VERSION_MAJOR-prefix"
"v$LFS_VERSION_MAJOR" \
"v$LFS_VERSION_MAJOR-prefix"
# build release notes
- name: create-release
@@ -254,10 +251,10 @@ jobs:
curl -sS -X POST -H "authorization: token ${{secrets.BOT_TOKEN}}" \
"$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/releases" \
-d "$(jq -n --rawfile release release.txt '{
tag_name: env.LFS2_VERSION,
name: env.LFS2_VERSION | rtrimstr(".0"),
tag_name: env.LFS_VERSION,
name: env.LFS_VERSION | rtrimstr(".0"),
target_commitish: "${{github.event.workflow_run.head_sha}}",
draft: env.LFS2_VERSION | endswith(".0"),
draft: env.LFS_VERSION | endswith(".0"),
body: $release,
}' | tee /dev/stderr)"

View File

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

View File

@@ -14,14 +14,14 @@ env:
jobs:
# run tests
test:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
arch: [x86_64, thumb, mips, powerpc]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -102,142 +102,142 @@ jobs:
- name: cov
if: ${{matrix.arch == 'x86_64'}}
run: |
make lfs2.cov.csv
./scripts/cov.py -u lfs2.cov.csv
make lfs.cov.csv
./scripts/cov.py -u lfs.cov.csv
mkdir -p cov
cp lfs2.cov.csv cov/cov.csv
cp lfs.cov.csv cov/cov.csv
# find compile-time measurements
- name: sizes
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_ASSERT \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR" \
make lfs.code.csv lfs.data.csv lfs.stack.csv lfs.structs.csv
./scripts/structs.py -u lfs.structs.csv
./scripts/summary.py lfs.code.csv lfs.data.csv lfs.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}.structs.csv
cp lfs.code.csv sizes/${{matrix.arch}}.code.csv
cp lfs.data.csv sizes/${{matrix.arch}}.data.csv
cp lfs.stack.csv sizes/${{matrix.arch}}.stack.csv
cp lfs.structs.csv sizes/${{matrix.arch}}.structs.csv
- name: sizes-readonly
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_ASSERT \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR \
-DLFS2_READONLY" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_READONLY" \
make lfs.code.csv lfs.data.csv lfs.stack.csv lfs.structs.csv
./scripts/structs.py -u lfs.structs.csv
./scripts/summary.py lfs.code.csv lfs.data.csv lfs.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}-readonly.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}-readonly.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-readonly.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-readonly.structs.csv
cp lfs.code.csv sizes/${{matrix.arch}}-readonly.code.csv
cp lfs.data.csv sizes/${{matrix.arch}}-readonly.data.csv
cp lfs.stack.csv sizes/${{matrix.arch}}-readonly.stack.csv
cp lfs.structs.csv sizes/${{matrix.arch}}-readonly.structs.csv
- name: sizes-threadsafe
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_ASSERT \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR \
-DLFS2_THREADSAFE" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_THREADSAFE" \
make lfs.code.csv lfs.data.csv lfs.stack.csv lfs.structs.csv
./scripts/structs.py -u lfs.structs.csv
./scripts/summary.py lfs.code.csv lfs.data.csv lfs.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}-threadsafe.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}-threadsafe.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-threadsafe.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-threadsafe.structs.csv
cp lfs.code.csv sizes/${{matrix.arch}}-threadsafe.code.csv
cp lfs.data.csv sizes/${{matrix.arch}}-threadsafe.data.csv
cp lfs.stack.csv sizes/${{matrix.arch}}-threadsafe.stack.csv
cp lfs.structs.csv sizes/${{matrix.arch}}-threadsafe.structs.csv
- name: sizes-multiversion
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_ASSERT \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR \
-DLFS2_MULTIVERSION" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_MULTIVERSION" \
make lfs.code.csv lfs.data.csv lfs.stack.csv lfs.structs.csv
./scripts/structs.py -u lfs.structs.csv
./scripts/summary.py lfs.code.csv lfs.data.csv lfs.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}-multiversion.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}-multiversion.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-multiversion.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-multiversion.structs.csv
cp lfs.code.csv sizes/${{matrix.arch}}-multiversion.code.csv
cp lfs.data.csv sizes/${{matrix.arch}}-multiversion.data.csv
cp lfs.stack.csv sizes/${{matrix.arch}}-multiversion.stack.csv
cp lfs.structs.csv sizes/${{matrix.arch}}-multiversion.structs.csv
- name: sizes-migrate
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_ASSERT \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR \
-DLFS2_MIGRATE" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-DLFS_NO_ASSERT \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-DLFS_MIGRATE" \
make lfs.code.csv lfs.data.csv lfs.stack.csv lfs.structs.csv
./scripts/structs.py -u lfs.structs.csv
./scripts/summary.py lfs.code.csv lfs.data.csv lfs.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}-migrate.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}-migrate.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-migrate.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-migrate.structs.csv
cp lfs.code.csv sizes/${{matrix.arch}}-migrate.code.csv
cp lfs.data.csv sizes/${{matrix.arch}}-migrate.data.csv
cp lfs.stack.csv sizes/${{matrix.arch}}-migrate.stack.csv
cp lfs.structs.csv sizes/${{matrix.arch}}-migrate.structs.csv
- name: sizes-error-asserts
run: |
make clean
CFLAGS="$CFLAGS \
-DLFS2_NO_DEBUG \
-DLFS2_NO_WARN \
-DLFS2_NO_ERROR \
-D'LFS2_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \
make lfs2.code.csv lfs2.data.csv lfs2.stack.csv lfs2.structs.csv
./scripts/structs.py -u lfs2.structs.csv
./scripts/summary.py lfs2.code.csv lfs2.data.csv lfs2.stack.csv \
-DLFS_NO_DEBUG \
-DLFS_NO_WARN \
-DLFS_NO_ERROR \
-D'LFS_ASSERT(test)=do {if(!(test)) {return -1;}} while(0)'" \
make lfs.code.csv lfs.data.csv lfs.stack.csv lfs.structs.csv
./scripts/structs.py -u lfs.structs.csv
./scripts/summary.py lfs.code.csv lfs.data.csv lfs.stack.csv \
-bfunction \
-fcode=code_size \
-fdata=data_size \
-fstack=stack_limit --max=stack_limit
mkdir -p sizes
cp lfs2.code.csv sizes/${{matrix.arch}}-error-asserts.code.csv
cp lfs2.data.csv sizes/${{matrix.arch}}-error-asserts.data.csv
cp lfs2.stack.csv sizes/${{matrix.arch}}-error-asserts.stack.csv
cp lfs2.structs.csv sizes/${{matrix.arch}}-error-asserts.structs.csv
cp lfs.code.csv sizes/${{matrix.arch}}-error-asserts.code.csv
cp lfs.data.csv sizes/${{matrix.arch}}-error-asserts.data.csv
cp lfs.stack.csv sizes/${{matrix.arch}}-error-asserts.stack.csv
cp lfs.structs.csv sizes/${{matrix.arch}}-error-asserts.structs.csv
# create size statuses
- name: upload-sizes
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: sizes-${{matrix.arch}}
name: sizes
path: sizes
- name: status-sizes
run: |
@@ -273,16 +273,16 @@ jobs:
}' | tee status/$(basename $f .csv).json
done
- name: upload-status-sizes
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: status-sizes-${{matrix.arch}}
name: status
path: status
retention-days: 1
# create cov statuses
- name: upload-cov
if: ${{matrix.arch == 'x86_64'}}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: cov
path: cov
@@ -317,11 +317,11 @@ jobs:
target_step: env.STEP,
}' | tee status/$(basename $f .csv)-$s.json
done
- name: upload-status-cov
- name: upload-status-sizes
if: ${{matrix.arch == 'x86_64'}}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: status-cov
name: status
path: status
retention-days: 1
@@ -329,14 +329,14 @@ jobs:
#
# this grows exponentially, so it doesn't turn out to be that many
test-pls:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
pls: [1, 2]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -357,11 +357,11 @@ jobs:
TESTFLAGS="$TESTFLAGS -P${{matrix.pls}} test_dirs test_relocations" \
make test
# run with LFS2_NO_INTRINSICS to make sure that works
# run with LFS_NO_INTRINSICS to make sure that works
test-no-intrinsics:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -372,52 +372,13 @@ jobs:
python3 --version
- name: test-no-intrinsics
run: |
CFLAGS="$CFLAGS -DLFS2_NO_INTRINSICS" make test
CFLAGS="$CFLAGS -DLFS_NO_INTRINSICS" make test
test-shrink:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install
run: |
# need a few things
sudo apt-get update -qq
sudo apt-get install -qq gcc python3 python3-pip
pip3 install toml
gcc --version
python3 --version
- name: test-no-intrinsics
run: |
CFLAGS="$CFLAGS -DLFS2_SHRINKNONRELOCATING" make test
# run with all trace options enabled to at least make sure these
# all compile
test-yes-trace:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install
run: |
# need a few things
sudo apt-get update -qq
sudo apt-get install -qq gcc python3 python3-pip
pip3 install toml
gcc --version
python3 --version
- name: test-yes-trace
run: |
CFLAGS="$CFLAGS \
-DLFS2_YES_TRACE \
-DLFS2_RAMBD_YES_TRACE \
-DLFS2_FILEBD_YES_TRACE \
-DLFS2_RAMBD_YES_TRACE" \
make test
# run LFS2_MULTIVERSION tests
# run LFS_MULTIVERSION tests
test-multiversion:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -428,13 +389,13 @@ jobs:
python3 --version
- name: test-multiversion
run: |
CFLAGS="$CFLAGS -DLFS2_MULTIVERSION" make test
CFLAGS="$CFLAGS -DLFS_MULTIVERSION" make test
# run tests on the older version lfs22.0
test-lfs22_0:
runs-on: ubuntu-latest
# run tests on the older version lfs2.0
test-lfs2_0:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -443,17 +404,17 @@ jobs:
pip3 install toml
gcc --version
python3 --version
- name: test-lfs22_0
- name: test-lfs2_0
run: |
CFLAGS="$CFLAGS -DLFS2_MULTIVERSION" \
CFLAGS="$CFLAGS -DLFS_MULTIVERSION" \
TESTFLAGS="$TESTFLAGS -DDISK_VERSION=0x00020000" \
make test
# run under Valgrind to check for memory errors
test-valgrind:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -470,11 +431,12 @@ jobs:
TESTFLAGS="$TESTFLAGS --valgrind --context=1024 -Gdefault -Pnone" \
make test
# compile/run with Clang, mostly to check for Clang-specific warnings
# test that compilation is warning free under clang
# run with Clang, mostly to check for Clang-specific warnings
test-clang:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -484,16 +446,20 @@ jobs:
python3 --version
- name: test-clang
run: |
CC=clang \
make test
# override CFLAGS since Clang does not support -fcallgraph-info
# and -ftrack-macro-expansions
make \
CC=clang \
CFLAGS="$CFLAGS -MMD -g3 -I. -std=c99 -Wall -Wextra -pedantic" \
test
# run benchmarks
#
# note there's no real benefit to running these on multiple archs
bench:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -508,24 +474,24 @@ jobs:
make bench
# find bench results
make lfs2.bench.csv
./scripts/summary.py lfs2.bench.csv \
make lfs.bench.csv
./scripts/summary.py lfs.bench.csv \
-bsuite \
-freaded=bench_readed \
-fproged=bench_proged \
-ferased=bench_erased
mkdir -p bench
cp lfs2.bench.csv bench/bench.csv
cp lfs.bench.csv bench/bench.csv
# find perfbd results
make lfs2.perfbd.csv
./scripts/perfbd.py -u lfs2.perfbd.csv
make lfs.perfbd.csv
./scripts/perfbd.py -u lfs.perfbd.csv
mkdir -p bench
cp lfs2.perfbd.csv bench/perfbd.csv
cp lfs.perfbd.csv bench/perfbd.csv
# create bench statuses
- name: upload-bench
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: bench
path: bench
@@ -559,24 +525,24 @@ jobs:
}' | tee status/$(basename $f .csv)-$s.json
done
- name: upload-status-bench
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: status-bench
name: status
path: status
retention-days: 1
# run compatibility tests using the current master as the previous version
test-compat:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}}
# checkout the current pr target into lfs2p
- uses: actions/checkout@v4
# checkout the current pr target into lfsp
- uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}}
with:
ref: ${{github.event.pull_request.base.ref}}
path: lfs2p
path: lfsp
- name: install
if: ${{github.event_name == 'pull_request'}}
run: |
@@ -586,27 +552,27 @@ jobs:
pip3 install toml
gcc --version
python3 --version
# adjust prefix of lfs2p
# adjust prefix of lfsp
- name: changeprefix
if: ${{github.event_name == 'pull_request'}}
run: |
./scripts/changeprefix.py lfs2 lfs2p lfs2p/*.h lfs2p/*.c
./scripts/changeprefix.py lfs lfsp lfsp/*.h lfsp/*.c
- name: test-compat
if: ${{github.event_name == 'pull_request'}}
run: |
TESTS=tests/test_compat.toml \
SRC="$(find . lfs2p -name '*.c' -maxdepth 1 \
SRC="$(find . lfsp -name '*.c' -maxdepth 1 \
-and -not -name '*.t.*' \
-and -not -name '*.b.*')" \
CFLAGS="-DLFS2P=lfs2p/lfs2p.h" \
CFLAGS="-DLFSP=lfsp/lfsp.h" \
make test
# self-host with littlefs-fuse for a fuzz-like test
fuse:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: ${{!endsWith(github.ref, '-prefix')}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -616,7 +582,7 @@ jobs:
gcc --version
python3 --version
fusermount -V
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
repository: littlefs-project/littlefs-fuse
ref: v2
@@ -639,8 +605,8 @@ jobs:
# self-host test
make -C littlefs-fuse
littlefs-fuse/lfs2 --format $LOOP
littlefs-fuse/lfs2 $LOOP mount
littlefs-fuse/lfs --format $LOOP
littlefs-fuse/lfs $LOOP mount
ls mount
mkdir mount/littlefs
@@ -653,10 +619,10 @@ jobs:
# test migration using littlefs-fuse
migrate:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: ${{!endsWith(github.ref, '-prefix')}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: install
run: |
# need a few things
@@ -666,12 +632,12 @@ jobs:
gcc --version
python3 --version
fusermount -V
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
repository: littlefs-project/littlefs-fuse
ref: v2
path: v2
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
repository: littlefs-project/littlefs-fuse
ref: v1
@@ -696,8 +662,8 @@ jobs:
make -C v2
# run self-host test with v1
v1/lfs2 --format $LOOP
v1/lfs2 $LOOP mount
v1/lfs --format $LOOP
v1/lfs $LOOP mount
ls mount
mkdir mount/littlefs
@@ -712,8 +678,8 @@ jobs:
cd ../..
fusermount -u mount
v2/lfs2 --migrate $LOOP
v2/lfs2 $LOOP mount
v2/lfs --migrate $LOOP
v2/lfs $LOOP mount
# run self-host test with v2 right where we left off
ls mount
@@ -725,10 +691,10 @@ jobs:
# status related tasks that run after tests
status:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: [test, bench]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
if: ${{github.event_name == 'pull_request'}}
- name: install
if: ${{github.event_name == 'pull_request'}}
@@ -738,26 +704,23 @@ jobs:
pip3 install toml
gcc --version
python3 --version
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v2
if: ${{github.event_name == 'pull_request'}}
continue-on-error: true
with:
pattern: '{sizes,sizes-*}'
merge-multiple: true
name: sizes
path: sizes
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v2
if: ${{github.event_name == 'pull_request'}}
continue-on-error: true
with:
pattern: '{cov,cov-*}'
merge-multiple: true
name: cov
path: cov
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v2
if: ${{github.event_name == 'pull_request'}}
continue-on-error: true
with:
pattern: '{bench,bench-*}'
merge-multiple: true
name: bench
path: bench
# try to find results from tests
@@ -899,7 +862,7 @@ jobs:
body: $comment,
}' | tee comment/comment.json
- name: upload-comment
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: comment
path: comment

20
.gitignore vendored
View File

@@ -9,21 +9,21 @@
*.gcno
*.gcda
*.perf
lfs2
lfs
liblfs.a
# Testing things
runners/test_runner
runners/bench_runner
lfs2.code.csv
lfs2.data.csv
lfs2.stack.csv
lfs2.structs.csv
lfs2.cov.csv
lfs2.perf.csv
lfs2.perfbd.csv
lfs2.test.csv
lfs2.bench.csv
lfs.code.csv
lfs.data.csv
lfs.stack.csv
lfs.structs.csv
lfs.cov.csv
lfs.perf.csv
lfs.perfbd.csv
lfs.test.csv
lfs.bench.csv
# Misc
tags

124
Makefile
View File

@@ -2,7 +2,7 @@
BUILDDIR ?= .
# overridable target/src/tools/flags/etc
ifneq ($(wildcard test.c main.c),)
TARGET ?= $(BUILDDIR)/lfs2
TARGET ?= $(BUILDDIR)/lfs
else
TARGET ?= $(BUILDDIR)/liblfs.a
endif
@@ -18,12 +18,6 @@ VALGRIND ?= valgrind
GDB ?= gdb
PERF ?= perf
# guess clang or gcc (clang sometimes masquerades as gcc because of
# course it does)
ifneq ($(shell $(CC) --version | grep clang),)
NO_GCC = 1
endif
SRC ?= $(filter-out $(wildcard *.t.* *.b.*),$(wildcard *.c))
OBJ := $(SRC:%.c=$(BUILDDIR)/%.o)
DEP := $(SRC:%.c=$(BUILDDIR)/%.d)
@@ -65,22 +59,19 @@ BENCH_PERF := $(BENCH_RUNNER:%=%.perf)
BENCH_TRACE := $(BENCH_RUNNER:%=%.trace)
BENCH_CSV := $(BENCH_RUNNER:%=%.csv)
CFLAGS += -fcallgraph-info=su
CFLAGS += -g3
CFLAGS += -I.
CFLAGS += -std=c99 -Wall -Wextra -pedantic
CFLAGS += -Wmissing-prototypes
ifndef NO_GCC
CFLAGS += -fcallgraph-info=su
CFLAGS += -ftrack-macro-expansion=0
endif
ifdef DEBUG
CFLAGS += -O0
else
CFLAGS += -Os
endif
ifdef TRACE
CFLAGS += -DLFS2_YES_TRACE
CFLAGS += -DLFS_YES_TRACE
endif
ifdef YES_COV
CFLAGS += --coverage
@@ -210,43 +201,43 @@ help:
## Find the per-function code size
.PHONY: code
code: CODEFLAGS+=-S
code: $(OBJ) $(BUILDDIR)/lfs2.code.csv
code: $(OBJ) $(BUILDDIR)/lfs.code.csv
./scripts/code.py $(OBJ) $(CODEFLAGS)
## Compare per-function code size
.PHONY: code-diff
code-diff: $(OBJ)
./scripts/code.py $^ $(CODEFLAGS) -d $(BUILDDIR)/lfs2.code.csv
./scripts/code.py $^ $(CODEFLAGS) -d $(BUILDDIR)/lfs.code.csv
## Find the per-function data size
.PHONY: data
data: DATAFLAGS+=-S
data: $(OBJ) $(BUILDDIR)/lfs2.data.csv
data: $(OBJ) $(BUILDDIR)/lfs.data.csv
./scripts/data.py $(OBJ) $(DATAFLAGS)
## Compare per-function data size
.PHONY: data-diff
data-diff: $(OBJ)
./scripts/data.py $^ $(DATAFLAGS) -d $(BUILDDIR)/lfs2.data.csv
./scripts/data.py $^ $(DATAFLAGS) -d $(BUILDDIR)/lfs.data.csv
## Find the per-function stack usage
.PHONY: stack
stack: STACKFLAGS+=-S
stack: $(CI) $(BUILDDIR)/lfs2.stack.csv
stack: $(CI) $(BUILDDIR)/lfs.stack.csv
./scripts/stack.py $(CI) $(STACKFLAGS)
## Compare per-function stack usage
.PHONY: stack-diff
stack-diff: $(CI)
./scripts/stack.py $^ $(STACKFLAGS) -d $(BUILDDIR)/lfs2.stack.csv
./scripts/stack.py $^ $(STACKFLAGS) -d $(BUILDDIR)/lfs.stack.csv
## Find function sizes
.PHONY: funcs
funcs: SUMMARYFLAGS+=-S
funcs: \
$(BUILDDIR)/lfs2.code.csv \
$(BUILDDIR)/lfs2.data.csv \
$(BUILDDIR)/lfs2.stack.csv
$(BUILDDIR)/lfs.code.csv \
$(BUILDDIR)/lfs.data.csv \
$(BUILDDIR)/lfs.stack.csv
$(strip ./scripts/summary.py $^ \
-bfunction \
-fcode=code_size \
@@ -267,26 +258,26 @@ funcs-diff: $(OBJ) $(CI)
-fdata=data_size \
-fstack=stack_limit --max=stack \
$(SUMMARYFLAGS) -d <(./scripts/summary.py \
$(BUILDDIR)/lfs2.code.csv \
$(BUILDDIR)/lfs2.data.csv \
$(BUILDDIR)/lfs2.stack.csv \
$(BUILDDIR)/lfs.code.csv \
$(BUILDDIR)/lfs.data.csv \
$(BUILDDIR)/lfs.stack.csv \
-q $(SUMMARYFLAGS) -o-))
## Find struct sizes
.PHONY: structs
structs: STRUCTSFLAGS+=-S
structs: $(OBJ) $(BUILDDIR)/lfs2.structs.csv
structs: $(OBJ) $(BUILDDIR)/lfs.structs.csv
./scripts/structs.py $(OBJ) $(STRUCTSFLAGS)
## Compare struct sizes
.PHONY: structs-diff
structs-diff: $(OBJ)
./scripts/structs.py $^ $(STRUCTSFLAGS) -d $(BUILDDIR)/lfs2.structs.csv
./scripts/structs.py $^ $(STRUCTSFLAGS) -d $(BUILDDIR)/lfs.structs.csv
## Find the line/branch coverage after a test run
.PHONY: cov
cov: COVFLAGS+=-s
cov: $(GCDA) $(BUILDDIR)/lfs2.cov.csv
cov: $(GCDA) $(BUILDDIR)/lfs.cov.csv
$(strip ./scripts/cov.py $(GCDA) \
$(patsubst %,-F%,$(SRC)) \
$(COVFLAGS))
@@ -296,12 +287,12 @@ cov: $(GCDA) $(BUILDDIR)/lfs2.cov.csv
cov-diff: $(GCDA)
$(strip ./scripts/cov.py $^ \
$(patsubst %,-F%,$(SRC)) \
$(COVFLAGS) -d $(BUILDDIR)/lfs2.cov.csv)
$(COVFLAGS) -d $(BUILDDIR)/lfs.cov.csv)
## Find the perf results after bench run with YES_PERF
.PHONY: perf
perf: PERFFLAGS+=-S
perf: $(BENCH_PERF) $(BUILDDIR)/lfs2.perf.csv
perf: $(BENCH_PERF) $(BUILDDIR)/lfs.perf.csv
$(strip ./scripts/perf.py $(BENCH_PERF) \
$(patsubst %,-F%,$(SRC)) \
$(PERFFLAGS))
@@ -311,12 +302,12 @@ perf: $(BENCH_PERF) $(BUILDDIR)/lfs2.perf.csv
perf-diff: $(BENCH_PERF)
$(strip ./scripts/perf.py $^ \
$(patsubst %,-F%,$(SRC)) \
$(PERFFLAGS) -d $(BUILDDIR)/lfs2.perf.csv)
$(PERFFLAGS) -d $(BUILDDIR)/lfs.perf.csv)
## Find the perfbd results after a bench run
.PHONY: perfbd
perfbd: PERFBDFLAGS+=-S
perfbd: $(BENCH_TRACE) $(BUILDDIR)/lfs2.perfbd.csv
perfbd: $(BENCH_TRACE) $(BUILDDIR)/lfs.perfbd.csv
$(strip ./scripts/perfbd.py $(BENCH_RUNNER) $(BENCH_TRACE) \
$(patsubst %,-F%,$(SRC)) \
$(PERFBDFLAGS))
@@ -326,15 +317,15 @@ perfbd: $(BENCH_TRACE) $(BUILDDIR)/lfs2.perfbd.csv
perfbd-diff: $(BENCH_TRACE)
$(strip ./scripts/perfbd.py $(BENCH_RUNNER) $^ \
$(patsubst %,-F%,$(SRC)) \
$(PERFBDFLAGS) -d $(BUILDDIR)/lfs2.perfbd.csv)
$(PERFBDFLAGS) -d $(BUILDDIR)/lfs.perfbd.csv)
## Find a summary of compile-time sizes
.PHONY: summary sizes
summary sizes: \
$(BUILDDIR)/lfs2.code.csv \
$(BUILDDIR)/lfs2.data.csv \
$(BUILDDIR)/lfs2.stack.csv \
$(BUILDDIR)/lfs2.structs.csv
$(BUILDDIR)/lfs.code.csv \
$(BUILDDIR)/lfs.data.csv \
$(BUILDDIR)/lfs.stack.csv \
$(BUILDDIR)/lfs.structs.csv
$(strip ./scripts/summary.py $^ \
-fcode=code_size \
-fdata=data_size \
@@ -356,10 +347,10 @@ summary-diff sizes-diff: $(OBJ) $(CI)
-fstack=stack_limit --max=stack \
-fstructs=struct_size \
-Y $(SUMMARYFLAGS) -d <(./scripts/summary.py \
$(BUILDDIR)/lfs2.code.csv \
$(BUILDDIR)/lfs2.data.csv \
$(BUILDDIR)/lfs2.stack.csv \
$(BUILDDIR)/lfs2.structs.csv \
$(BUILDDIR)/lfs.code.csv \
$(BUILDDIR)/lfs.data.csv \
$(BUILDDIR)/lfs.stack.csv \
$(BUILDDIR)/lfs.structs.csv \
-q $(SUMMARYFLAGS) -o-))
## Build the test-runner
@@ -400,7 +391,7 @@ test-list: test-runner
## Summarize the testmarks
.PHONY: testmarks
testmarks: SUMMARYFLAGS+=-spassed
testmarks: $(TEST_CSV) $(BUILDDIR)/lfs2.test.csv
testmarks: $(TEST_CSV) $(BUILDDIR)/lfs.test.csv
$(strip ./scripts/summary.py $(TEST_CSV) \
-bsuite \
-fpassed=test_passed \
@@ -412,7 +403,7 @@ testmarks-diff: $(TEST_CSV)
$(strip ./scripts/summary.py $^ \
-bsuite \
-fpassed=test_passed \
$(SUMMARYFLAGS) -d $(BUILDDIR)/lfs2.test.csv)
$(SUMMARYFLAGS) -d $(BUILDDIR)/lfs.test.csv)
## Build the bench-runner
.PHONY: bench-runner build-bench
@@ -452,7 +443,7 @@ bench-list: bench-runner
## Summarize the benchmarks
.PHONY: benchmarks
benchmarks: SUMMARYFLAGS+=-Serased -Sproged -Sreaded
benchmarks: $(BENCH_CSV) $(BUILDDIR)/lfs2.bench.csv
benchmarks: $(BENCH_CSV) $(BUILDDIR)/lfs.bench.csv
$(strip ./scripts/summary.py $(BENCH_CSV) \
-bsuite \
-freaded=bench_readed \
@@ -468,54 +459,53 @@ benchmarks-diff: $(BENCH_CSV)
-freaded=bench_readed \
-fproged=bench_proged \
-ferased=bench_erased \
$(SUMMARYFLAGS) -d $(BUILDDIR)/lfs2.bench.csv)
$(SUMMARYFLAGS) -d $(BUILDDIR)/lfs.bench.csv)
# rules
-include $(DEP)
-include $(TEST_DEP)
-include $(BENCH_DEP)
.SUFFIXES:
.SECONDARY:
$(BUILDDIR)/lfs2: $(OBJ)
$(BUILDDIR)/lfs: $(OBJ)
$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
$(BUILDDIR)/liblfs.a: $(OBJ)
$(AR) rcs $@ $^
$(BUILDDIR)/lfs2.code.csv: $(OBJ)
$(BUILDDIR)/lfs.code.csv: $(OBJ)
./scripts/code.py $^ -q $(CODEFLAGS) -o $@
$(BUILDDIR)/lfs2.data.csv: $(OBJ)
$(BUILDDIR)/lfs.data.csv: $(OBJ)
./scripts/data.py $^ -q $(DATAFLAGS) -o $@
$(BUILDDIR)/lfs2.stack.csv: $(CI)
$(BUILDDIR)/lfs.stack.csv: $(CI)
./scripts/stack.py $^ -q $(STACKFLAGS) -o $@
$(BUILDDIR)/lfs2.structs.csv: $(OBJ)
$(BUILDDIR)/lfs.structs.csv: $(OBJ)
./scripts/structs.py $^ -q $(STRUCTSFLAGS) -o $@
$(BUILDDIR)/lfs2.cov.csv: $(GCDA)
$(BUILDDIR)/lfs.cov.csv: $(GCDA)
$(strip ./scripts/cov.py $^ \
$(patsubst %,-F%,$(SRC)) \
-q $(COVFLAGS) -o $@)
$(BUILDDIR)/lfs2.perf.csv: $(BENCH_PERF)
$(BUILDDIR)/lfs.perf.csv: $(BENCH_PERF)
$(strip ./scripts/perf.py $^ \
$(patsubst %,-F%,$(SRC)) \
-q $(PERFFLAGS) -o $@)
$(BUILDDIR)/lfs2.perfbd.csv: $(BENCH_TRACE)
$(BUILDDIR)/lfs.perfbd.csv: $(BENCH_TRACE)
$(strip ./scripts/perfbd.py $(BENCH_RUNNER) $^ \
$(patsubst %,-F%,$(SRC)) \
-q $(PERFBDFLAGS) -o $@)
$(BUILDDIR)/lfs2.test.csv: $(TEST_CSV)
$(BUILDDIR)/lfs.test.csv: $(TEST_CSV)
cp $^ $@
$(BUILDDIR)/lfs2.bench.csv: $(BENCH_CSV)
$(BUILDDIR)/lfs.bench.csv: $(BENCH_CSV)
cp $^ $@
$(BUILDDIR)/runners/test_runner: $(TEST_OBJ)
@@ -536,10 +526,10 @@ $(BUILDDIR)/%.s: %.c
$(CC) -S $(CFLAGS) $< -o $@
$(BUILDDIR)/%.c: %.a.c
./scripts/prettyasserts.py -p LFS2_ASSERT $< -o $@
./scripts/prettyasserts.py -p LFS_ASSERT $< -o $@
$(BUILDDIR)/%.c: $(BUILDDIR)/%.a.c
./scripts/prettyasserts.py -p LFS2_ASSERT $< -o $@
./scripts/prettyasserts.py -p LFS_ASSERT $< -o $@
$(BUILDDIR)/%.t.a.c: %.toml
./scripts/test.py -c $< $(TESTCFLAGS) -o $@
@@ -556,17 +546,17 @@ $(BUILDDIR)/%.b.a.c: %.c $(BENCHES)
## Clean everything
.PHONY: clean
clean:
rm -f $(BUILDDIR)/lfs2
rm -f $(BUILDDIR)/lfs
rm -f $(BUILDDIR)/liblfs.a
rm -f $(BUILDDIR)/lfs2.code.csv
rm -f $(BUILDDIR)/lfs2.data.csv
rm -f $(BUILDDIR)/lfs2.stack.csv
rm -f $(BUILDDIR)/lfs2.structs.csv
rm -f $(BUILDDIR)/lfs2.cov.csv
rm -f $(BUILDDIR)/lfs2.perf.csv
rm -f $(BUILDDIR)/lfs2.perfbd.csv
rm -f $(BUILDDIR)/lfs2.test.csv
rm -f $(BUILDDIR)/lfs2.bench.csv
rm -f $(BUILDDIR)/lfs.code.csv
rm -f $(BUILDDIR)/lfs.data.csv
rm -f $(BUILDDIR)/lfs.stack.csv
rm -f $(BUILDDIR)/lfs.structs.csv
rm -f $(BUILDDIR)/lfs.cov.csv
rm -f $(BUILDDIR)/lfs.perf.csv
rm -f $(BUILDDIR)/lfs.perfbd.csv
rm -f $(BUILDDIR)/lfs.test.csv
rm -f $(BUILDDIR)/lfs.bench.csv
rm -f $(OBJ)
rm -f $(DEP)
rm -f $(ASM)

130
README.md
View File

@@ -32,14 +32,14 @@ main runs. The program can be interrupted at any time without losing track
of how many times it has been booted and without corrupting the filesystem:
``` c
#include "lfs2.h"
#include "lfs.h"
// variables used by the filesystem
lfs2_t lfs2;
lfs2_file_t file;
lfs_t lfs;
lfs_file_t file;
// configuration of the filesystem is provided by this struct
const struct lfs2_config cfg = {
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
@@ -59,30 +59,30 @@ const struct lfs2_config cfg = {
// entry point
int main(void) {
// mount the filesystem
int err = lfs2_mount(&lfs2, &cfg);
int err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
lfs2_format(&lfs2, &cfg);
lfs2_mount(&lfs2, &cfg);
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
}
// read current count
uint32_t boot_count = 0;
lfs2_file_open(&lfs2, &file, "boot_count", LFS2_O_RDWR | LFS2_O_CREAT);
lfs2_file_read(&lfs2, &file, &boot_count, sizeof(boot_count));
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// update boot count
boot_count += 1;
lfs2_file_rewind(&lfs2, &file);
lfs2_file_write(&lfs2, &file, &boot_count, sizeof(boot_count));
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully
lfs2_file_close(&lfs2, &file);
lfs_file_close(&lfs, &file);
// release any resources we were using
lfs2_unmount(&lfs2);
lfs_unmount(&lfs);
// print the boot count
printf("boot_count: %d\n", boot_count);
@@ -92,7 +92,7 @@ int main(void) {
## Usage
Detailed documentation (or at least as much detail as is currently available)
can be found in the comments in [lfs2.h](lfs2.h).
can be found in the comments in [lfs.h](lfs.h).
littlefs takes in a configuration structure that defines how the filesystem
operates. The configuration struct provides the filesystem with the block
@@ -100,9 +100,9 @@ device operations and dimensions, tweakable parameters that tradeoff memory
usage for performance, and optional static buffers if the user wants to avoid
dynamic memory.
The state of the littlefs is stored in the `lfs2_t` type which is left up
The state of the littlefs is stored in the `lfs_t` type which is left up
to the user to allocate, allowing multiple filesystems to be in use
simultaneously. With the `lfs2_t` and configuration struct, a user can
simultaneously. With the `lfs_t` and configuration struct, a user can
format a block device or mount the filesystem.
Once mounted, the littlefs provides a full set of POSIX-like file and
@@ -119,11 +119,11 @@ Littlefs is written in C, and specifically should compile with any compiler
that conforms to the `C99` standard.
All littlefs calls have the potential to return a negative error code. The
errors can be either one of those found in the `enum lfs2_error` in
[lfs2.h](lfs2.h), or an error returned by the user's block device operations.
errors can be either one of those found in the `enum lfs_error` in
[lfs.h](lfs.h), or an error returned by the user's block device operations.
In the configuration struct, the `prog` and `erase` function provided by the
user may return a `LFS2_ERR_CORRUPT` error if the implementation already can
user may return a `LFS_ERR_CORRUPT` error if the implementation already can
detect corrupt blocks. However, the wear leveling does not depend on the return
code of these functions, instead all data is read back and checked for
integrity.
@@ -192,54 +192,13 @@ More details on how littlefs works can be found in [DESIGN.md](DESIGN.md) and
## Testing
The littlefs comes with a test suite designed to run on a PC using the
[emulated block device](bd/lfs2_testbd.h) found in the `bd` directory.
[emulated block device](bd/lfs_testbd.h) found in the `bd` directory.
The tests assume a Linux environment and can be started with make:
``` bash
make test
```
Tests are implemented in C in the .toml files found in the `tests` directory.
When developing a feature or fixing a bug, it is frequently useful to run a
single test case or suite of tests:
``` bash
./scripts/test.py -l runners/test_runner # list available test suites
./scripts/test.py -L runners/test_runner test_dirs # list available test cases
./scripts/test.py runners/test_runner test_dirs # run a specific test suite
```
If an assert fails in a test, test.py will try to print information about the
failure:
``` bash
tests/test_dirs.toml:1:failure: test_dirs_root:1g12gg2 (PROG_SIZE=16, ERASE_SIZE=512) failed
tests/test_dirs.toml:5:assert: assert failed with 0, expected eq 42
lfs2_mount(&lfs2, cfg) => 42;
```
This includes the test id, which can be passed to test.py to run only that
specific test permutation:
``` bash
./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 # run a specific test permutation
./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 --gdb # drop into gdb on failure
```
Some other flags that may be useful:
```bash
./scripts/test.py runners/test_runner -b -j # run tests in parallel
./scripts/test.py runners/test_runner -v -O- # redirect stdout to stdout
./scripts/test.py runners/test_runner -ddisk # capture resulting disk image
```
See `-h/--help` for a full list of available flags:
``` bash
./scripts/test.py --help
```
## License
The littlefs is provided under the [BSD-3-Clause] license. See
@@ -267,40 +226,16 @@ License Identifiers that are here available: http://spdx.org/licenses/
to create images of the filesystem on your PC. Check if littlefs will fit
your needs, create images for a later download to the target memory or
inspect the content of a binary image of the target memory.
- [littlefs-toy] - A command-line tool for creating and working with littlefs
images. Uses syntax similar to tar command for ease of use. Supports working
on littlefs images embedded inside another file (firmware image, etc).
- [littlefs2-rust] - A Rust wrapper for littlefs. This project allows you
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 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.
- [ramcrc32bd] - An example block device using littlefs's 32-bit CRC for
error-correction.
- [ramrsbd] - An example block device using Reed-Solomon codes for
error-correction.
- [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.
- [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.
@@ -319,24 +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
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
[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/
[littlefs-toy]: https://github.com/tjko/littlefs-toy
[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
[mklittlefs]: https://github.com/earlephilhower/mklittlefs
[pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb
[ramcrc32bd]: https://github.com/geky/ramcrc32bd
[ramrsbd]: https://github.com/geky/ramrsbd
[Lua RTOS]: https://github.com/whitecatboard/Lua-RTOS-ESP32
[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

47
SPEC.md
View File

@@ -1,7 +1,7 @@
## littlefs technical specification
This is the technical specification of the little filesystem with on-disk
version lfs22.1. This document covers the technical details of how the littlefs
version lfs2.1. This document covers the technical details of how the littlefs
is stored on disk for introspection and tooling. This document assumes you are
familiar with the design of the littlefs, for more info on how littlefs works
check out [DESIGN.md](DESIGN.md).
@@ -294,7 +294,7 @@ Metadata tag fields:
What follows is an exhaustive list of metadata in littlefs.
---
#### `0x401` LFS2_TYPE_CREATE
#### `0x401` LFS_TYPE_CREATE
Creates a new file with this id. Note that files in a metadata block
don't necessarily need a create tag. All a create does is move over any
@@ -305,14 +305,14 @@ The create and delete tags allow littlefs to keep files in a directory
ordered alphabetically by filename.
---
#### `0x4ff` LFS2_TYPE_DELETE
#### `0x4ff` LFS_TYPE_DELETE
Deletes the file with this id. An inverse to create, this tag moves over
any files neighboring this id similar to a deletion from an imaginary
array of files.
---
#### `0x0xx` LFS2_TYPE_NAME
#### `0x0xx` LFS_TYPE_NAME
Associates the id with a file name and file type.
@@ -345,14 +345,14 @@ Name fields:
2. **file name** - File name stored as an ASCII string.
---
#### `0x001` LFS2_TYPE_REG
#### `0x001` LFS_TYPE_REG
Initializes the id + name as a regular file.
How each file is stored depends on its struct tag, which is described below.
---
#### `0x002` LFS2_TYPE_DIR
#### `0x002` LFS_TYPE_DIR
Initializes the id + name as a directory.
@@ -361,7 +361,7 @@ each pair containing any number of files in alphabetical order. A pointer to
the directory is stored in the struct tag, which is described below.
---
#### `0x0ff` LFS2_TYPE_SUPERBLOCK
#### `0x0ff` LFS_TYPE_SUPERBLOCK
Initializes the id as a superblock entry.
@@ -441,13 +441,12 @@ 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 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.
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.
---
#### `0x2xx` LFS2_TYPE_STRUCT
#### `0x2xx` LFS_TYPE_STRUCT
Associates the id with an on-disk data structure.
@@ -458,7 +457,7 @@ Any type of struct supersedes all other structs associated with the id. For
example, appending a ctz-struct replaces an inline-struct on the same file.
---
#### `0x200` LFS2_TYPE_DIRSTRUCT
#### `0x200` LFS_TYPE_DIRSTRUCT
Gives the id a directory data structure.
@@ -500,7 +499,7 @@ Dir-struct fields:
in the directory.
---
#### `0x201` LFS2_TYPE_INLINESTRUCT
#### `0x201` LFS_TYPE_INLINESTRUCT
Gives the id an inline data structure.
@@ -524,7 +523,7 @@ Inline-struct fields:
1. **Inline data** - File data stored directly in the metadata-pair.
---
#### `0x202` LFS2_TYPE_CTZSTRUCT
#### `0x202` LFS_TYPE_CTZSTRUCT
Gives the id a CTZ skip-list data structure.
@@ -579,7 +578,7 @@ CTZ-struct fields:
2. **File size (32-bits)** - Size of the file in bytes.
---
#### `0x3xx` LFS2_TYPE_USERATTR
#### `0x3xx` LFS_TYPE_USERATTR
Attaches a user attribute to an id.
@@ -613,7 +612,7 @@ User-attr fields:
2. **Attr data** - The data associated with the user attribute.
---
#### `0x6xx` LFS2_TYPE_TAIL
#### `0x6xx` LFS_TYPE_TAIL
Provides the tail pointer for the metadata pair itself.
@@ -679,7 +678,7 @@ Tail fields:
2. **Metadata pair (8-bytes)** - Pointer to the next metadata-pair.
---
#### `0x600` LFS2_TYPE_SOFTTAIL
#### `0x600` LFS_TYPE_SOFTTAIL
Provides a tail pointer that points to the next metadata pair in the
filesystem.
@@ -688,7 +687,7 @@ In this case, the next metadata pair is not a part of our current directory
and should only be followed when traversing the entire filesystem.
---
#### `0x601` LFS2_TYPE_HARDTAIL
#### `0x601` LFS_TYPE_HARDTAIL
Provides a tail pointer that points to the next metadata pair in the
directory.
@@ -699,7 +698,7 @@ metadata pair should only contain filenames greater than any filename in the
current pair.
---
#### `0x7xx` LFS2_TYPE_GSTATE
#### `0x7xx` LFS_TYPE_GSTATE
Provides delta bits for global state entries.
@@ -729,7 +728,7 @@ is stored in the chunk field. Currently, the only global state is move state,
which is outlined below.
---
#### `0x7ff` LFS2_TYPE_MOVESTATE
#### `0x7ff` LFS_TYPE_MOVESTATE
Provides delta bits for the global move state.
@@ -782,7 +781,7 @@ Move state fields:
the move.
---
#### `0x5xx` LFS2_TYPE_CRC
#### `0x5xx` LFS_TYPE_CRC
Last but not least, the CRC tag marks the end of a commit and provides a
checksum for any commits to the metadata block.
@@ -827,9 +826,9 @@ CRC fields:
are made about the contents.
---
#### `0x5ff` LFS2_TYPE_FCRC
#### `0x5ff` LFS_TYPE_FCRC
Added in lfs22.1, the optional FCRC tag contains a checksum of some amount of
Added in lfs2.1, the optional FCRC tag contains a checksum of some amount of
bytes in the next commit at the time it was erased. This allows us to ensure
that we only ever program erased bytes, even if a previous commit failed due
to power-loss.

View File

@@ -1,739 +0,0 @@
/*
* Emulating block device, wraps filebd and rambd while providing a bunch
* of hooks for testing littlefs in various conditions.
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#endif
#include "bd/lfs2_emubd.h"
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#endif
// access to lazily-allocated/copy-on-write blocks
//
// Note we can only modify a block if we have exclusive access to it (rc == 1)
//
static lfs2_emubd_block_t *lfs2_emubd_incblock(lfs2_emubd_block_t *block) {
if (block) {
block->rc += 1;
}
return block;
}
static void lfs2_emubd_decblock(lfs2_emubd_block_t *block) {
if (block) {
block->rc -= 1;
if (block->rc == 0) {
free(block);
}
}
}
static lfs2_emubd_block_t *lfs2_emubd_mutblock(
const struct lfs2_config *cfg,
lfs2_emubd_block_t **block) {
lfs2_emubd_t *bd = cfg->context;
lfs2_emubd_block_t *block_ = *block;
if (block_ && block_->rc == 1) {
// rc == 1? can modify
return block_;
} else if (block_) {
// rc > 1? need to create a copy
lfs2_emubd_block_t *nblock = malloc(
sizeof(lfs2_emubd_block_t) + bd->cfg->erase_size);
if (!nblock) {
return NULL;
}
memcpy(nblock, block_,
sizeof(lfs2_emubd_block_t) + bd->cfg->erase_size);
nblock->rc = 1;
lfs2_emubd_decblock(block_);
*block = nblock;
return nblock;
} else {
// no block? need to allocate
lfs2_emubd_block_t *nblock = malloc(
sizeof(lfs2_emubd_block_t) + bd->cfg->erase_size);
if (!nblock) {
return NULL;
}
nblock->rc = 1;
nblock->wear = 0;
// zero for consistency
memset(nblock->data,
(bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0,
bd->cfg->erase_size);
*block = nblock;
return nblock;
}
}
// emubd create/destroy
int lfs2_emubd_create(const struct lfs2_config *cfg,
const struct lfs2_emubd_config *bdcfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
".erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", "
".powerloss_behavior=%"PRIu8", .powerloss_cb=%p, "
".powerloss_data=%p, .track_branches=%d})",
(void*)cfg, cfg->context,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
(void*)bdcfg,
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
bdcfg->erase_count, bdcfg->erase_value, bdcfg->erase_cycles,
bdcfg->badblock_behavior, bdcfg->power_cycles,
bdcfg->powerloss_behavior, (void*)(uintptr_t)bdcfg->powerloss_cb,
bdcfg->powerloss_data, bdcfg->track_branches);
lfs2_emubd_t *bd = cfg->context;
bd->cfg = bdcfg;
// allocate our block array, all blocks start as uninitialized
bd->blocks = malloc(bd->cfg->erase_count * sizeof(lfs2_emubd_block_t*));
if (!bd->blocks) {
LFS2_EMUBD_TRACE("lfs2_emubd_create -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
memset(bd->blocks, 0, bd->cfg->erase_count * sizeof(lfs2_emubd_block_t*));
// setup testing things
bd->readed = 0;
bd->proged = 0;
bd->erased = 0;
bd->power_cycles = bd->cfg->power_cycles;
bd->ooo_block = -1;
bd->ooo_data = NULL;
bd->disk = NULL;
if (bd->cfg->disk_path) {
bd->disk = malloc(sizeof(lfs2_emubd_disk_t));
if (!bd->disk) {
LFS2_EMUBD_TRACE("lfs2_emubd_create -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
bd->disk->rc = 1;
bd->disk->scratch = NULL;
#ifdef _WIN32
bd->disk->fd = open(bd->cfg->disk_path,
O_RDWR | O_CREAT | O_BINARY, 0666);
#else
bd->disk->fd = open(bd->cfg->disk_path,
O_RDWR | O_CREAT, 0666);
#endif
if (bd->disk->fd < 0) {
int err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_create -> %d", err);
return err;
}
// if we're emulating erase values, we can keep a block around in
// memory of just the erase state to speed up emulated erases
if (bd->cfg->erase_value != -1) {
bd->disk->scratch = malloc(bd->cfg->erase_size);
if (!bd->disk->scratch) {
LFS2_EMUBD_TRACE("lfs2_emubd_create -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
memset(bd->disk->scratch,
bd->cfg->erase_value,
bd->cfg->erase_size);
// go ahead and erase all of the disk, otherwise the file will not
// match our internal representation
for (size_t i = 0; i < bd->cfg->erase_count; i++) {
ssize_t res = write(bd->disk->fd,
bd->disk->scratch,
bd->cfg->erase_size);
if (res < 0) {
int err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_create -> %d", err);
return err;
}
}
}
}
LFS2_EMUBD_TRACE("lfs2_emubd_create -> %d", 0);
return 0;
}
int lfs2_emubd_destroy(const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_destroy(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
// decrement reference counts
for (lfs2_block_t i = 0; i < bd->cfg->erase_count; i++) {
lfs2_emubd_decblock(bd->blocks[i]);
}
free(bd->blocks);
// clean up other resources
lfs2_emubd_decblock(bd->ooo_data);
if (bd->disk) {
bd->disk->rc -= 1;
if (bd->disk->rc == 0) {
close(bd->disk->fd);
free(bd->disk->scratch);
free(bd->disk);
}
}
LFS2_EMUBD_TRACE("lfs2_emubd_destroy -> %d", 0);
return 0;
}
// powerloss hook
static int lfs2_emubd_powerloss(const struct lfs2_config *cfg) {
lfs2_emubd_t *bd = cfg->context;
// emulate out-of-order writes?
lfs2_emubd_block_t *ooo_data = NULL;
if (bd->cfg->powerloss_behavior == LFS2_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] = lfs2_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 == LFS2_EMUBD_POWERLOSS_OOO
&& bd->ooo_block != -1) {
lfs2_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
int lfs2_emubd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size) {
LFS2_EMUBD_TRACE("lfs2_emubd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_emubd_t *bd = cfg->context;
// check if read is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS2_ASSERT(off % bd->cfg->read_size == 0);
LFS2_ASSERT(size % bd->cfg->read_size == 0);
LFS2_ASSERT(off+size <= bd->cfg->erase_size);
// get the block
const lfs2_emubd_block_t *b = bd->blocks[block];
if (b) {
// block bad?
if (bd->cfg->erase_cycles && b->wear >= bd->cfg->erase_cycles &&
bd->cfg->badblock_behavior == LFS2_EMUBD_BADBLOCK_READERROR) {
LFS2_EMUBD_TRACE("lfs2_emubd_read -> %d", LFS2_ERR_CORRUPT);
return LFS2_ERR_CORRUPT;
}
// read data
memcpy(buffer, &b->data[off], size);
} else {
// zero for consistency
memset(buffer,
(bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0,
size);
}
// track reads
bd->readed += size;
if (bd->cfg->read_sleep) {
int err = nanosleep(&(struct timespec){
.tv_sec=bd->cfg->read_sleep/1000000000,
.tv_nsec=bd->cfg->read_sleep%1000000000},
NULL);
if (err) {
err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_read -> %d", err);
return err;
}
}
LFS2_EMUBD_TRACE("lfs2_emubd_read -> %d", 0);
return 0;
}
int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_emubd_t *bd = cfg->context;
// check if write is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS2_ASSERT(off % bd->cfg->prog_size == 0);
LFS2_ASSERT(size % bd->cfg->prog_size == 0);
LFS2_ASSERT(off+size <= bd->cfg->erase_size);
// get the block
lfs2_emubd_block_t *b = lfs2_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
// block bad?
if (bd->cfg->erase_cycles && b->wear >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS2_EMUBD_BADBLOCK_PROGERROR) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", LFS2_ERR_CORRUPT);
return LFS2_ERR_CORRUPT;
} else if (bd->cfg->badblock_behavior ==
LFS2_EMUBD_BADBLOCK_PROGNOOP ||
bd->cfg->badblock_behavior ==
LFS2_EMUBD_BADBLOCK_ERASENOOP) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", 0);
return 0;
}
}
// were we erased properly?
if (bd->cfg->erase_value != -1) {
for (lfs2_off_t i = 0; i < size; i++) {
LFS2_ASSERT(b->data[off+i] == bd->cfg->erase_value);
}
}
// prog data
memcpy(&b->data[off], buffer, size);
// mirror to disk file?
if (bd->disk) {
off_t res1 = lseek(bd->disk->fd,
(off_t)block*bd->cfg->erase_size + (off_t)off,
SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", err);
return err;
}
ssize_t res2 = write(bd->disk->fd, buffer, size);
if (res2 < 0) {
int err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", err);
return err;
}
}
// track progs
bd->proged += size;
if (bd->cfg->prog_sleep) {
int err = nanosleep(&(struct timespec){
.tv_sec=bd->cfg->prog_sleep/1000000000,
.tv_nsec=bd->cfg->prog_sleep%1000000000},
NULL);
if (err) {
err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", err);
return err;
}
}
// lose power?
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
int err = lfs2_emubd_powerloss(cfg);
if (err) {
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", err);
return err;
}
}
}
LFS2_EMUBD_TRACE("lfs2_emubd_prog -> %d", 0);
return 0;
}
int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
LFS2_EMUBD_TRACE("lfs2_emubd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
(void*)cfg, block, ((lfs2_emubd_t*)cfg->context)->cfg->erase_size);
lfs2_emubd_t *bd = cfg->context;
// check if erase is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
// emulate out-of-order writes? save first write
if (bd->cfg->powerloss_behavior == LFS2_EMUBD_POWERLOSS_OOO
&& bd->ooo_block == -1) {
bd->ooo_block = block;
bd->ooo_data = lfs2_emubd_incblock(bd->blocks[block]);
}
// get the block
lfs2_emubd_block_t *b = lfs2_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
// block bad?
if (bd->cfg->erase_cycles) {
if (b->wear >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS2_EMUBD_BADBLOCK_ERASEERROR) {
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", LFS2_ERR_CORRUPT);
return LFS2_ERR_CORRUPT;
} else if (bd->cfg->badblock_behavior ==
LFS2_EMUBD_BADBLOCK_ERASENOOP) {
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", 0);
return 0;
}
} else {
// mark wear
b->wear += 1;
}
}
// emulate an erase value?
if (bd->cfg->erase_value != -1) {
memset(b->data, bd->cfg->erase_value, bd->cfg->erase_size);
// mirror to disk file?
if (bd->disk) {
off_t res1 = lseek(bd->disk->fd,
(off_t)block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", err);
return err;
}
ssize_t res2 = write(bd->disk->fd,
bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
int err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", err);
return err;
}
}
}
// track erases
bd->erased += bd->cfg->erase_size;
if (bd->cfg->erase_sleep) {
int err = nanosleep(&(struct timespec){
.tv_sec=bd->cfg->erase_sleep/1000000000,
.tv_nsec=bd->cfg->erase_sleep%1000000000},
NULL);
if (err) {
err = -errno;
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", err);
return err;
}
}
// lose power?
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
int err = lfs2_emubd_powerloss(cfg);
if (err) {
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", err);
return err;
}
}
}
LFS2_EMUBD_TRACE("lfs2_emubd_erase -> %d", 0);
return 0;
}
int lfs2_emubd_sync(const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_sync(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
// emulate out-of-order writes? reset first write, writes
// cannot be out-of-order across sync
if (bd->cfg->powerloss_behavior == LFS2_EMUBD_POWERLOSS_OOO) {
lfs2_emubd_decblock(bd->ooo_data);
bd->ooo_block = -1;
bd->ooo_data = NULL;
}
LFS2_EMUBD_TRACE("lfs2_emubd_sync -> %d", 0);
return 0;
}
/// Additional extended API for driving test features ///
static int lfs2_emubd_crc_(const struct lfs2_config *cfg,
lfs2_block_t block, uint32_t *crc) {
lfs2_emubd_t *bd = cfg->context;
// check if crc is valid
LFS2_ASSERT(block < cfg->block_count);
// crc the block
uint32_t crc_ = 0xffffffff;
const lfs2_emubd_block_t *b = bd->blocks[block];
if (b) {
crc_ = lfs2_crc(crc_, b->data, cfg->block_size);
} else {
uint8_t erase_value = (bd->cfg->erase_value != -1)
? bd->cfg->erase_value
: 0;
for (lfs2_size_t i = 0; i < cfg->block_size; i++) {
crc_ = lfs2_crc(crc_, &erase_value, 1);
}
}
*crc = 0xffffffff ^ crc_;
return 0;
}
int lfs2_emubd_crc(const struct lfs2_config *cfg,
lfs2_block_t block, uint32_t *crc) {
LFS2_EMUBD_TRACE("lfs2_emubd_crc(%p, %"PRIu32", %p)",
(void*)cfg, block, crc);
int err = lfs2_emubd_crc_(cfg, block, crc);
LFS2_EMUBD_TRACE("lfs2_emubd_crc -> %d", err);
return err;
}
int lfs2_emubd_bdcrc(const struct lfs2_config *cfg, uint32_t *crc) {
LFS2_EMUBD_TRACE("lfs2_emubd_bdcrc(%p, %p)", (void*)cfg, crc);
uint32_t crc_ = 0xffffffff;
for (lfs2_block_t i = 0; i < cfg->block_count; i++) {
uint32_t i_crc;
int err = lfs2_emubd_crc_(cfg, i, &i_crc);
if (err) {
LFS2_EMUBD_TRACE("lfs2_emubd_bdcrc -> %d", err);
return err;
}
crc_ = lfs2_crc(crc_, &i_crc, sizeof(uint32_t));
}
*crc = 0xffffffff ^ crc_;
LFS2_EMUBD_TRACE("lfs2_emubd_bdcrc -> %d", 0);
return 0;
}
lfs2_emubd_sio_t lfs2_emubd_readed(const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_readed(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
LFS2_EMUBD_TRACE("lfs2_emubd_readed -> %"PRIu64, bd->readed);
return bd->readed;
}
lfs2_emubd_sio_t lfs2_emubd_proged(const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_proged(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
LFS2_EMUBD_TRACE("lfs2_emubd_proged -> %"PRIu64, bd->proged);
return bd->proged;
}
lfs2_emubd_sio_t lfs2_emubd_erased(const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_erased(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
LFS2_EMUBD_TRACE("lfs2_emubd_erased -> %"PRIu64, bd->erased);
return bd->erased;
}
int lfs2_emubd_setreaded(const struct lfs2_config *cfg, lfs2_emubd_io_t readed) {
LFS2_EMUBD_TRACE("lfs2_emubd_setreaded(%p, %"PRIu64")", (void*)cfg, readed);
lfs2_emubd_t *bd = cfg->context;
bd->readed = readed;
LFS2_EMUBD_TRACE("lfs2_emubd_setreaded -> %d", 0);
return 0;
}
int lfs2_emubd_setproged(const struct lfs2_config *cfg, lfs2_emubd_io_t proged) {
LFS2_EMUBD_TRACE("lfs2_emubd_setproged(%p, %"PRIu64")", (void*)cfg, proged);
lfs2_emubd_t *bd = cfg->context;
bd->proged = proged;
LFS2_EMUBD_TRACE("lfs2_emubd_setproged -> %d", 0);
return 0;
}
int lfs2_emubd_seterased(const struct lfs2_config *cfg, lfs2_emubd_io_t erased) {
LFS2_EMUBD_TRACE("lfs2_emubd_seterased(%p, %"PRIu64")", (void*)cfg, erased);
lfs2_emubd_t *bd = cfg->context;
bd->erased = erased;
LFS2_EMUBD_TRACE("lfs2_emubd_seterased -> %d", 0);
return 0;
}
lfs2_emubd_swear_t lfs2_emubd_wear(const struct lfs2_config *cfg,
lfs2_block_t block) {
LFS2_EMUBD_TRACE("lfs2_emubd_wear(%p, %"PRIu32")", (void*)cfg, block);
lfs2_emubd_t *bd = cfg->context;
// check if block is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
// get the wear
lfs2_emubd_wear_t wear;
const lfs2_emubd_block_t *b = bd->blocks[block];
if (b) {
wear = b->wear;
} else {
wear = 0;
}
LFS2_EMUBD_TRACE("lfs2_emubd_wear -> %"PRIi32, wear);
return wear;
}
int lfs2_emubd_setwear(const struct lfs2_config *cfg,
lfs2_block_t block, lfs2_emubd_wear_t wear) {
LFS2_EMUBD_TRACE("lfs2_emubd_setwear(%p, %"PRIu32", %"PRIi32")",
(void*)cfg, block, wear);
lfs2_emubd_t *bd = cfg->context;
// check if block is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
// set the wear
lfs2_emubd_block_t *b = lfs2_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS2_EMUBD_TRACE("lfs2_emubd_setwear -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
b->wear = wear;
LFS2_EMUBD_TRACE("lfs2_emubd_setwear -> %d", 0);
return 0;
}
lfs2_emubd_spowercycles_t lfs2_emubd_powercycles(
const struct lfs2_config *cfg) {
LFS2_EMUBD_TRACE("lfs2_emubd_powercycles(%p)", (void*)cfg);
lfs2_emubd_t *bd = cfg->context;
LFS2_EMUBD_TRACE("lfs2_emubd_powercycles -> %"PRIi32, bd->power_cycles);
return bd->power_cycles;
}
int lfs2_emubd_setpowercycles(const struct lfs2_config *cfg,
lfs2_emubd_powercycles_t power_cycles) {
LFS2_EMUBD_TRACE("lfs2_emubd_setpowercycles(%p, %"PRIi32")",
(void*)cfg, power_cycles);
lfs2_emubd_t *bd = cfg->context;
bd->power_cycles = power_cycles;
LFS2_EMUBD_TRACE("lfs2_emubd_powercycles -> %d", 0);
return 0;
}
int lfs2_emubd_copy(const struct lfs2_config *cfg, lfs2_emubd_t *copy) {
LFS2_EMUBD_TRACE("lfs2_emubd_copy(%p, %p)", (void*)cfg, (void*)copy);
lfs2_emubd_t *bd = cfg->context;
// lazily copy over our block array
copy->blocks = malloc(bd->cfg->erase_count * sizeof(lfs2_emubd_block_t*));
if (!copy->blocks) {
LFS2_EMUBD_TRACE("lfs2_emubd_copy -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
for (size_t i = 0; i < bd->cfg->erase_count; i++) {
copy->blocks[i] = lfs2_emubd_incblock(bd->blocks[i]);
}
// other state
copy->readed = bd->readed;
copy->proged = bd->proged;
copy->erased = bd->erased;
copy->power_cycles = bd->power_cycles;
copy->ooo_block = bd->ooo_block;
copy->ooo_data = lfs2_emubd_incblock(bd->ooo_data);
copy->disk = bd->disk;
if (copy->disk) {
copy->disk->rc += 1;
}
copy->cfg = bd->cfg;
LFS2_EMUBD_TRACE("lfs2_emubd_copy -> %d", 0);
return 0;
}

View File

@@ -1,82 +0,0 @@
/*
* Block device emulated in a file
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_FILEBD_H
#define LFS2_FILEBD_H
#include "lfs2.h"
#include "lfs2_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifndef LFS2_FILEBD_TRACE
#ifdef LFS2_FILEBD_YES_TRACE
#define LFS2_FILEBD_TRACE(...) LFS2_TRACE(__VA_ARGS__)
#else
#define LFS2_FILEBD_TRACE(...)
#endif
#endif
// filebd config
struct lfs2_filebd_config {
// Minimum size of a read operation in bytes.
lfs2_size_t read_size;
// Minimum size of a program operation in bytes.
lfs2_size_t prog_size;
// Size of an erase operation in bytes.
lfs2_size_t erase_size;
// Number of erase blocks on the device.
lfs2_size_t erase_count;
};
// filebd state
typedef struct lfs2_filebd {
int fd;
const struct lfs2_filebd_config *cfg;
} lfs2_filebd_t;
// Create a file block device
int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path,
const struct lfs2_filebd_config *bdcfg);
// Clean up memory associated with block device
int lfs2_filebd_destroy(const struct lfs2_config *cfg);
// Read a block
int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
// Sync the block device
int lfs2_filebd_sync(const struct lfs2_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -1,118 +0,0 @@
/*
* Block device emulated in RAM
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "bd/lfs2_rambd.h"
int lfs2_rambd_create(const struct lfs2_config *cfg,
const struct lfs2_rambd_config *bdcfg) {
LFS2_RAMBD_TRACE("lfs2_rambd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
".buffer=%p})",
(void*)cfg, cfg->context,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
(void*)bdcfg,
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
bdcfg->erase_count, bdcfg->buffer);
lfs2_rambd_t *bd = cfg->context;
bd->cfg = bdcfg;
// allocate buffer?
if (bd->cfg->buffer) {
bd->buffer = bd->cfg->buffer;
} else {
bd->buffer = lfs2_malloc(bd->cfg->erase_size * bd->cfg->erase_count);
if (!bd->buffer) {
LFS2_RAMBD_TRACE("lfs2_rambd_create -> %d", LFS2_ERR_NOMEM);
return LFS2_ERR_NOMEM;
}
}
// zero for reproducibility
memset(bd->buffer, 0, bd->cfg->erase_size * bd->cfg->erase_count);
LFS2_RAMBD_TRACE("lfs2_rambd_create -> %d", 0);
return 0;
}
int lfs2_rambd_destroy(const struct lfs2_config *cfg) {
LFS2_RAMBD_TRACE("lfs2_rambd_destroy(%p)", (void*)cfg);
// clean up memory
lfs2_rambd_t *bd = cfg->context;
if (!bd->cfg->buffer) {
lfs2_free(bd->buffer);
}
LFS2_RAMBD_TRACE("lfs2_rambd_destroy -> %d", 0);
return 0;
}
int lfs2_rambd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size) {
LFS2_RAMBD_TRACE("lfs2_rambd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_rambd_t *bd = cfg->context;
// check if read is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS2_ASSERT(off % bd->cfg->read_size == 0);
LFS2_ASSERT(size % bd->cfg->read_size == 0);
LFS2_ASSERT(off+size <= bd->cfg->erase_size);
// read data
memcpy(buffer, &bd->buffer[block*bd->cfg->erase_size + off], size);
LFS2_RAMBD_TRACE("lfs2_rambd_read -> %d", 0);
return 0;
}
int lfs2_rambd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size) {
LFS2_RAMBD_TRACE("lfs2_rambd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_rambd_t *bd = cfg->context;
// check if write is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS2_ASSERT(off % bd->cfg->prog_size == 0);
LFS2_ASSERT(size % bd->cfg->prog_size == 0);
LFS2_ASSERT(off+size <= bd->cfg->erase_size);
// program data
memcpy(&bd->buffer[block*bd->cfg->erase_size + off], buffer, size);
LFS2_RAMBD_TRACE("lfs2_rambd_prog -> %d", 0);
return 0;
}
int lfs2_rambd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
LFS2_RAMBD_TRACE("lfs2_rambd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
(void*)cfg, block, ((lfs2_rambd_t*)cfg->context)->cfg->erase_size);
lfs2_rambd_t *bd = cfg->context;
// check if erase is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
// erase is a noop
(void)block;
LFS2_RAMBD_TRACE("lfs2_rambd_erase -> %d", 0);
return 0;
}
int lfs2_rambd_sync(const struct lfs2_config *cfg) {
LFS2_RAMBD_TRACE("lfs2_rambd_sync(%p)", (void*)cfg);
// sync is a noop
(void)cfg;
LFS2_RAMBD_TRACE("lfs2_rambd_sync -> %d", 0);
return 0;
}

View File

@@ -1,85 +0,0 @@
/*
* Block device emulated in RAM
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_RAMBD_H
#define LFS2_RAMBD_H
#include "lfs2.h"
#include "lfs2_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifndef LFS2_RAMBD_TRACE
#ifdef LFS2_RAMBD_YES_TRACE
#define LFS2_RAMBD_TRACE(...) LFS2_TRACE(__VA_ARGS__)
#else
#define LFS2_RAMBD_TRACE(...)
#endif
#endif
// rambd config
struct lfs2_rambd_config {
// Minimum size of a read operation in bytes.
lfs2_size_t read_size;
// Minimum size of a program operation in bytes.
lfs2_size_t prog_size;
// Size of an erase operation in bytes.
lfs2_size_t erase_size;
// Number of erase blocks on the device.
lfs2_size_t erase_count;
// Optional statically allocated buffer for the block device.
void *buffer;
};
// rambd state
typedef struct lfs2_rambd {
uint8_t *buffer;
const struct lfs2_rambd_config *cfg;
} lfs2_rambd_t;
// Create a RAM block device
int lfs2_rambd_create(const struct lfs2_config *cfg,
const struct lfs2_rambd_config *bdcfg);
// Clean up memory associated with block device
int lfs2_rambd_destroy(const struct lfs2_config *cfg);
// Read a block
int lfs2_rambd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs2_rambd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs2_rambd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
// Sync the block device
int lfs2_rambd_sync(const struct lfs2_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

645
bd/lfs_emubd.c Normal file
View File

@@ -0,0 +1,645 @@
/*
* Emulating block device, wraps filebd and rambd while providing a bunch
* of hooks for testing littlefs in various conditions.
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#endif
#include "bd/lfs_emubd.h"
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#endif
// access to lazily-allocated/copy-on-write blocks
//
// Note we can only modify a block if we have exclusive access to it (rc == 1)
//
static lfs_emubd_block_t *lfs_emubd_incblock(lfs_emubd_block_t *block) {
if (block) {
block->rc += 1;
}
return block;
}
static void lfs_emubd_decblock(lfs_emubd_block_t *block) {
if (block) {
block->rc -= 1;
if (block->rc == 0) {
free(block);
}
}
}
static lfs_emubd_block_t *lfs_emubd_mutblock(
const struct lfs_config *cfg,
lfs_emubd_block_t **block) {
lfs_emubd_t *bd = cfg->context;
lfs_emubd_block_t *block_ = *block;
if (block_ && block_->rc == 1) {
// rc == 1? can modify
return block_;
} else if (block_) {
// rc > 1? need to create a copy
lfs_emubd_block_t *nblock = malloc(
sizeof(lfs_emubd_block_t) + bd->cfg->erase_size);
if (!nblock) {
return NULL;
}
memcpy(nblock, block_,
sizeof(lfs_emubd_block_t) + bd->cfg->erase_size);
nblock->rc = 1;
lfs_emubd_decblock(block_);
*block = nblock;
return nblock;
} else {
// no block? need to allocate
lfs_emubd_block_t *nblock = malloc(
sizeof(lfs_emubd_block_t) + bd->cfg->erase_size);
if (!nblock) {
return NULL;
}
nblock->rc = 1;
nblock->wear = 0;
// zero for consistency
memset(nblock->data,
(bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0,
bd->cfg->erase_size);
*block = nblock;
return nblock;
}
}
// emubd create/destroy
int lfs_emubd_create(const struct lfs_config *cfg,
const struct lfs_emubd_config *bdcfg) {
LFS_EMUBD_TRACE("lfs_emubd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
".erase_value=%"PRId32", .erase_cycles=%"PRIu32", "
".badblock_behavior=%"PRIu8", .power_cycles=%"PRIu32", "
".powerloss_behavior=%"PRIu8", .powerloss_cb=%p, "
".powerloss_data=%p, .track_branches=%d})",
(void*)cfg, cfg->context,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
(void*)bdcfg,
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
bdcfg->erase_count, bdcfg->erase_value, bdcfg->erase_cycles,
bdcfg->badblock_behavior, bdcfg->power_cycles,
bdcfg->powerloss_behavior, (void*)(uintptr_t)bdcfg->powerloss_cb,
bdcfg->powerloss_data, bdcfg->track_branches);
lfs_emubd_t *bd = cfg->context;
bd->cfg = bdcfg;
// allocate our block array, all blocks start as uninitialized
bd->blocks = malloc(bd->cfg->erase_count * sizeof(lfs_emubd_block_t*));
if (!bd->blocks) {
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
memset(bd->blocks, 0, bd->cfg->erase_count * sizeof(lfs_emubd_block_t*));
// setup testing things
bd->readed = 0;
bd->proged = 0;
bd->erased = 0;
bd->power_cycles = bd->cfg->power_cycles;
bd->disk = NULL;
if (bd->cfg->disk_path) {
bd->disk = malloc(sizeof(lfs_emubd_disk_t));
if (!bd->disk) {
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
bd->disk->rc = 1;
bd->disk->scratch = NULL;
#ifdef _WIN32
bd->disk->fd = open(bd->cfg->disk_path,
O_RDWR | O_CREAT | O_BINARY, 0666);
#else
bd->disk->fd = open(bd->cfg->disk_path,
O_RDWR | O_CREAT, 0666);
#endif
if (bd->disk->fd < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", err);
return err;
}
// if we're emulating erase values, we can keep a block around in
// memory of just the erase state to speed up emulated erases
if (bd->cfg->erase_value != -1) {
bd->disk->scratch = malloc(bd->cfg->erase_size);
if (!bd->disk->scratch) {
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
memset(bd->disk->scratch,
bd->cfg->erase_value,
bd->cfg->erase_size);
// go ahead and erase all of the disk, otherwise the file will not
// match our internal representation
for (size_t i = 0; i < bd->cfg->erase_count; i++) {
ssize_t res = write(bd->disk->fd,
bd->disk->scratch,
bd->cfg->erase_size);
if (res < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", err);
return err;
}
}
}
}
LFS_EMUBD_TRACE("lfs_emubd_create -> %d", 0);
return 0;
}
int lfs_emubd_destroy(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_destroy(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
// decrement reference counts
for (lfs_block_t i = 0; i < bd->cfg->erase_count; i++) {
lfs_emubd_decblock(bd->blocks[i]);
}
free(bd->blocks);
// clean up other resources
if (bd->disk) {
bd->disk->rc -= 1;
if (bd->disk->rc == 0) {
close(bd->disk->fd);
free(bd->disk->scratch);
free(bd->disk);
}
}
LFS_EMUBD_TRACE("lfs_emubd_destroy -> %d", 0);
return 0;
}
// block device API
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_EMUBD_TRACE("lfs_emubd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs_emubd_t *bd = cfg->context;
// check if read is valid
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(off+size <= bd->cfg->erase_size);
// get the block
const lfs_emubd_block_t *b = bd->blocks[block];
if (b) {
// block bad?
if (bd->cfg->erase_cycles && b->wear >= bd->cfg->erase_cycles &&
bd->cfg->badblock_behavior == LFS_EMUBD_BADBLOCK_READERROR) {
LFS_EMUBD_TRACE("lfs_emubd_read -> %d", LFS_ERR_CORRUPT);
return LFS_ERR_CORRUPT;
}
// read data
memcpy(buffer, &b->data[off], size);
} else {
// zero for consistency
memset(buffer,
(bd->cfg->erase_value != -1) ? bd->cfg->erase_value : 0,
size);
}
// track reads
bd->readed += size;
if (bd->cfg->read_sleep) {
int err = nanosleep(&(struct timespec){
.tv_sec=bd->cfg->read_sleep/1000000000,
.tv_nsec=bd->cfg->read_sleep%1000000000},
NULL);
if (err) {
err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_read -> %d", err);
return err;
}
}
LFS_EMUBD_TRACE("lfs_emubd_read -> %d", 0);
return 0;
}
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_EMUBD_TRACE("lfs_emubd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs_emubd_t *bd = cfg->context;
// check if write is valid
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(off+size <= bd->cfg->erase_size);
// get the block
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
// block bad?
if (bd->cfg->erase_cycles && b->wear >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS_EMUBD_BADBLOCK_PROGERROR) {
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_CORRUPT);
return LFS_ERR_CORRUPT;
} else if (bd->cfg->badblock_behavior ==
LFS_EMUBD_BADBLOCK_PROGNOOP ||
bd->cfg->badblock_behavior ==
LFS_EMUBD_BADBLOCK_ERASENOOP) {
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", 0);
return 0;
}
}
// were we erased properly?
if (bd->cfg->erase_value != -1) {
for (lfs_off_t i = 0; i < size; i++) {
LFS_ASSERT(b->data[off+i] == bd->cfg->erase_value);
}
}
// prog data
memcpy(&b->data[off], buffer, size);
// mirror to disk file?
if (bd->disk) {
off_t res1 = lseek(bd->disk->fd,
(off_t)block*bd->cfg->erase_size + (off_t)off,
SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err);
return err;
}
ssize_t res2 = write(bd->disk->fd, buffer, size);
if (res2 < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err);
return err;
}
}
// track progs
bd->proged += size;
if (bd->cfg->prog_sleep) {
int err = nanosleep(&(struct timespec){
.tv_sec=bd->cfg->prog_sleep/1000000000,
.tv_nsec=bd->cfg->prog_sleep%1000000000},
NULL);
if (err) {
err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", err);
return err;
}
}
// lose power?
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
}
}
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", 0);
return 0;
}
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
LFS_EMUBD_TRACE("lfs_emubd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
(void*)cfg, block, ((lfs_emubd_t*)cfg->context)->cfg->erase_size);
lfs_emubd_t *bd = cfg->context;
// check if erase is valid
LFS_ASSERT(block < bd->cfg->erase_count);
// get the block
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS_EMUBD_TRACE("lfs_emubd_prog -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
// block bad?
if (bd->cfg->erase_cycles) {
if (b->wear >= bd->cfg->erase_cycles) {
if (bd->cfg->badblock_behavior ==
LFS_EMUBD_BADBLOCK_ERASEERROR) {
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", LFS_ERR_CORRUPT);
return LFS_ERR_CORRUPT;
} else if (bd->cfg->badblock_behavior ==
LFS_EMUBD_BADBLOCK_ERASENOOP) {
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", 0);
return 0;
}
} else {
// mark wear
b->wear += 1;
}
}
// emulate an erase value?
if (bd->cfg->erase_value != -1) {
memset(b->data, bd->cfg->erase_value, bd->cfg->erase_size);
// mirror to disk file?
if (bd->disk) {
off_t res1 = lseek(bd->disk->fd,
(off_t)block*bd->cfg->erase_size,
SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
return err;
}
ssize_t res2 = write(bd->disk->fd,
bd->disk->scratch,
bd->cfg->erase_size);
if (res2 < 0) {
int err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
return err;
}
}
}
// track erases
bd->erased += bd->cfg->erase_size;
if (bd->cfg->erase_sleep) {
int err = nanosleep(&(struct timespec){
.tv_sec=bd->cfg->erase_sleep/1000000000,
.tv_nsec=bd->cfg->erase_sleep%1000000000},
NULL);
if (err) {
err = -errno;
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", err);
return err;
}
}
// lose power?
if (bd->power_cycles > 0) {
bd->power_cycles -= 1;
if (bd->power_cycles == 0) {
// simulate power loss
bd->cfg->powerloss_cb(bd->cfg->powerloss_data);
}
}
LFS_EMUBD_TRACE("lfs_emubd_erase -> %d", 0);
return 0;
}
int lfs_emubd_sync(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_sync(%p)", (void*)cfg);
// do nothing
(void)cfg;
LFS_EMUBD_TRACE("lfs_emubd_sync -> %d", 0);
return 0;
}
/// Additional extended API for driving test features ///
static int lfs_emubd_rawcrc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) {
lfs_emubd_t *bd = cfg->context;
// check if crc is valid
LFS_ASSERT(block < cfg->block_count);
// crc the block
uint32_t crc_ = 0xffffffff;
const lfs_emubd_block_t *b = bd->blocks[block];
if (b) {
crc_ = lfs_crc(crc_, b->data, cfg->block_size);
} else {
uint8_t erase_value = (bd->cfg->erase_value != -1)
? bd->cfg->erase_value
: 0;
for (lfs_size_t i = 0; i < cfg->block_size; i++) {
crc_ = lfs_crc(crc_, &erase_value, 1);
}
}
*crc = 0xffffffff ^ crc_;
return 0;
}
int lfs_emubd_crc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc) {
LFS_EMUBD_TRACE("lfs_emubd_crc(%p, %"PRIu32", %p)",
(void*)cfg, block, crc);
int err = lfs_emubd_rawcrc(cfg, block, crc);
LFS_EMUBD_TRACE("lfs_emubd_crc -> %d", err);
return err;
}
int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc) {
LFS_EMUBD_TRACE("lfs_emubd_bdcrc(%p, %p)", (void*)cfg, crc);
uint32_t crc_ = 0xffffffff;
for (lfs_block_t i = 0; i < cfg->block_count; i++) {
uint32_t i_crc;
int err = lfs_emubd_rawcrc(cfg, i, &i_crc);
if (err) {
LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", err);
return err;
}
crc_ = lfs_crc(crc_, &i_crc, sizeof(uint32_t));
}
*crc = 0xffffffff ^ crc_;
LFS_EMUBD_TRACE("lfs_emubd_bdcrc -> %d", 0);
return 0;
}
lfs_emubd_sio_t lfs_emubd_readed(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_readed(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
LFS_EMUBD_TRACE("lfs_emubd_readed -> %"PRIu64, bd->readed);
return bd->readed;
}
lfs_emubd_sio_t lfs_emubd_proged(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_proged(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
LFS_EMUBD_TRACE("lfs_emubd_proged -> %"PRIu64, bd->proged);
return bd->proged;
}
lfs_emubd_sio_t lfs_emubd_erased(const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_erased(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
LFS_EMUBD_TRACE("lfs_emubd_erased -> %"PRIu64, bd->erased);
return bd->erased;
}
int lfs_emubd_setreaded(const struct lfs_config *cfg, lfs_emubd_io_t readed) {
LFS_EMUBD_TRACE("lfs_emubd_setreaded(%p, %"PRIu64")", (void*)cfg, readed);
lfs_emubd_t *bd = cfg->context;
bd->readed = readed;
LFS_EMUBD_TRACE("lfs_emubd_setreaded -> %d", 0);
return 0;
}
int lfs_emubd_setproged(const struct lfs_config *cfg, lfs_emubd_io_t proged) {
LFS_EMUBD_TRACE("lfs_emubd_setproged(%p, %"PRIu64")", (void*)cfg, proged);
lfs_emubd_t *bd = cfg->context;
bd->proged = proged;
LFS_EMUBD_TRACE("lfs_emubd_setproged -> %d", 0);
return 0;
}
int lfs_emubd_seterased(const struct lfs_config *cfg, lfs_emubd_io_t erased) {
LFS_EMUBD_TRACE("lfs_emubd_seterased(%p, %"PRIu64")", (void*)cfg, erased);
lfs_emubd_t *bd = cfg->context;
bd->erased = erased;
LFS_EMUBD_TRACE("lfs_emubd_seterased -> %d", 0);
return 0;
}
lfs_emubd_swear_t lfs_emubd_wear(const struct lfs_config *cfg,
lfs_block_t block) {
LFS_EMUBD_TRACE("lfs_emubd_wear(%p, %"PRIu32")", (void*)cfg, block);
lfs_emubd_t *bd = cfg->context;
// check if block is valid
LFS_ASSERT(block < bd->cfg->erase_count);
// get the wear
lfs_emubd_wear_t wear;
const lfs_emubd_block_t *b = bd->blocks[block];
if (b) {
wear = b->wear;
} else {
wear = 0;
}
LFS_EMUBD_TRACE("lfs_emubd_wear -> %"PRIi32, wear);
return wear;
}
int lfs_emubd_setwear(const struct lfs_config *cfg,
lfs_block_t block, lfs_emubd_wear_t wear) {
LFS_EMUBD_TRACE("lfs_emubd_setwear(%p, %"PRIu32", %"PRIi32")",
(void*)cfg, block, wear);
lfs_emubd_t *bd = cfg->context;
// check if block is valid
LFS_ASSERT(block < bd->cfg->erase_count);
// set the wear
lfs_emubd_block_t *b = lfs_emubd_mutblock(cfg, &bd->blocks[block]);
if (!b) {
LFS_EMUBD_TRACE("lfs_emubd_setwear -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
b->wear = wear;
LFS_EMUBD_TRACE("lfs_emubd_setwear -> %d", 0);
return 0;
}
lfs_emubd_spowercycles_t lfs_emubd_powercycles(
const struct lfs_config *cfg) {
LFS_EMUBD_TRACE("lfs_emubd_powercycles(%p)", (void*)cfg);
lfs_emubd_t *bd = cfg->context;
LFS_EMUBD_TRACE("lfs_emubd_powercycles -> %"PRIi32, bd->power_cycles);
return bd->power_cycles;
}
int lfs_emubd_setpowercycles(const struct lfs_config *cfg,
lfs_emubd_powercycles_t power_cycles) {
LFS_EMUBD_TRACE("lfs_emubd_setpowercycles(%p, %"PRIi32")",
(void*)cfg, power_cycles);
lfs_emubd_t *bd = cfg->context;
bd->power_cycles = power_cycles;
LFS_EMUBD_TRACE("lfs_emubd_powercycles -> %d", 0);
return 0;
}
int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy) {
LFS_EMUBD_TRACE("lfs_emubd_copy(%p, %p)", (void*)cfg, (void*)copy);
lfs_emubd_t *bd = cfg->context;
// lazily copy over our block array
copy->blocks = malloc(bd->cfg->erase_count * sizeof(lfs_emubd_block_t*));
if (!copy->blocks) {
LFS_EMUBD_TRACE("lfs_emubd_copy -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
for (size_t i = 0; i < bd->cfg->erase_count; i++) {
copy->blocks[i] = lfs_emubd_incblock(bd->blocks[i]);
}
// other state
copy->readed = bd->readed;
copy->proged = bd->proged;
copy->erased = bd->erased;
copy->power_cycles = bd->power_cycles;
copy->disk = bd->disk;
if (copy->disk) {
copy->disk->rc += 1;
}
copy->cfg = bd->cfg;
LFS_EMUBD_TRACE("lfs_emubd_copy -> %d", 0);
return 0;
}

View File

@@ -6,13 +6,13 @@
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_EMUBD_H
#define LFS2_EMUBD_H
#ifndef LFS_EMUBD_H
#define LFS_EMUBD_H
#include "lfs2.h"
#include "lfs2_util.h"
#include "bd/lfs2_rambd.h"
#include "bd/lfs2_filebd.h"
#include "lfs.h"
#include "lfs_util.h"
#include "bd/lfs_rambd.h"
#include "bd/lfs_filebd.h"
#ifdef __cplusplus
extern "C"
@@ -21,11 +21,11 @@ extern "C"
// Block device specific tracing
#ifndef LFS2_EMUBD_TRACE
#ifdef LFS2_EMUBD_YES_TRACE
#define LFS2_EMUBD_TRACE(...) LFS2_TRACE(__VA_ARGS__)
#ifndef LFS_EMUBD_TRACE
#ifdef LFS_EMUBD_YES_TRACE
#define LFS_EMUBD_TRACE(...) LFS_TRACE(__VA_ARGS__)
#else
#define LFS2_EMUBD_TRACE(...)
#define LFS_EMUBD_TRACE(...)
#endif
#endif
@@ -35,50 +35,49 @@ extern "C"
//
// Not that read-noop is not allowed. Read _must_ return a consistent (but
// may be arbitrary) value on every read.
typedef enum lfs2_emubd_badblock_behavior {
LFS2_EMUBD_BADBLOCK_PROGERROR = 0, // Error on prog
LFS2_EMUBD_BADBLOCK_ERASEERROR = 1, // Error on erase
LFS2_EMUBD_BADBLOCK_READERROR = 2, // Error on read
LFS2_EMUBD_BADBLOCK_PROGNOOP = 3, // Prog does nothing silently
LFS2_EMUBD_BADBLOCK_ERASENOOP = 4, // Erase does nothing silently
} lfs2_emubd_badblock_behavior_t;
typedef enum lfs_emubd_badblock_behavior {
LFS_EMUBD_BADBLOCK_PROGERROR,
LFS_EMUBD_BADBLOCK_ERASEERROR,
LFS_EMUBD_BADBLOCK_READERROR,
LFS_EMUBD_BADBLOCK_PROGNOOP,
LFS_EMUBD_BADBLOCK_ERASENOOP,
} lfs_emubd_badblock_behavior_t;
// Mode determining how power-loss behaves during testing. For now this
// only supports a noop behavior, leaving the data on-disk untouched.
typedef enum lfs2_emubd_powerloss_behavior {
LFS2_EMUBD_POWERLOSS_NOOP = 0, // Progs are atomic
LFS2_EMUBD_POWERLOSS_OOO = 1, // Blocks are written out-of-order
} lfs2_emubd_powerloss_behavior_t;
typedef enum lfs_emubd_powerloss_behavior {
LFS_EMUBD_POWERLOSS_NOOP,
} lfs_emubd_powerloss_behavior_t;
// Type for measuring read/program/erase operations
typedef uint64_t lfs2_emubd_io_t;
typedef int64_t lfs2_emubd_sio_t;
typedef uint64_t lfs_emubd_io_t;
typedef int64_t lfs_emubd_sio_t;
// Type for measuring wear
typedef uint32_t lfs2_emubd_wear_t;
typedef int32_t lfs2_emubd_swear_t;
typedef uint32_t lfs_emubd_wear_t;
typedef int32_t lfs_emubd_swear_t;
// Type for tracking power-cycles
typedef uint32_t lfs2_emubd_powercycles_t;
typedef int32_t lfs2_emubd_spowercycles_t;
typedef uint32_t lfs_emubd_powercycles_t;
typedef int32_t lfs_emubd_spowercycles_t;
// Type for delays in nanoseconds
typedef uint64_t lfs2_emubd_sleep_t;
typedef int64_t lfs2_emubd_ssleep_t;
typedef uint64_t lfs_emubd_sleep_t;
typedef int64_t lfs_emubd_ssleep_t;
// emubd config, this is required for testing
struct lfs2_emubd_config {
struct lfs_emubd_config {
// Minimum size of a read operation in bytes.
lfs2_size_t read_size;
lfs_size_t read_size;
// Minimum size of a program operation in bytes.
lfs2_size_t prog_size;
lfs_size_t prog_size;
// Size of an erase operation in bytes.
lfs2_size_t erase_size;
lfs_size_t erase_size;
// Number of erase blocks on the device.
lfs2_size_t erase_count;
lfs_size_t erase_count;
// 8-bit erase value to use for simulating erases. -1 does not simulate
// erases, which can speed up testing by avoiding the extra block-device
@@ -90,15 +89,15 @@ struct lfs2_emubd_config {
uint32_t erase_cycles;
// The mode determining how bad-blocks fail
lfs2_emubd_badblock_behavior_t badblock_behavior;
lfs_emubd_badblock_behavior_t badblock_behavior;
// Number of write operations (erase/prog) before triggering a power-loss.
// power_cycles=0 disables this. The exact behavior of power-loss is
// controlled by a combination of powerloss_behavior and powerloss_cb.
lfs2_emubd_powercycles_t power_cycles;
lfs_emubd_powercycles_t power_cycles;
// The mode determining how power-loss affects disk
lfs2_emubd_powerloss_behavior_t powerloss_behavior;
lfs_emubd_powerloss_behavior_t powerloss_behavior;
// Function to call to emulate power-loss. The exact behavior of power-loss
// is up to the runner to provide.
@@ -117,124 +116,122 @@ struct lfs2_emubd_config {
// Artificial delay in nanoseconds, there is no purpose for this other
// than slowing down the simulation.
lfs2_emubd_sleep_t read_sleep;
lfs_emubd_sleep_t read_sleep;
// Artificial delay in nanoseconds, there is no purpose for this other
// than slowing down the simulation.
lfs2_emubd_sleep_t prog_sleep;
lfs_emubd_sleep_t prog_sleep;
// Artificial delay in nanoseconds, there is no purpose for this other
// than slowing down the simulation.
lfs2_emubd_sleep_t erase_sleep;
lfs_emubd_sleep_t erase_sleep;
};
// A reference counted block
typedef struct lfs2_emubd_block {
typedef struct lfs_emubd_block {
uint32_t rc;
lfs2_emubd_wear_t wear;
lfs_emubd_wear_t wear;
uint8_t data[];
} lfs2_emubd_block_t;
} lfs_emubd_block_t;
// Disk mirror
typedef struct lfs2_emubd_disk {
typedef struct lfs_emubd_disk {
uint32_t rc;
int fd;
uint8_t *scratch;
} lfs2_emubd_disk_t;
} lfs_emubd_disk_t;
// emubd state
typedef struct lfs2_emubd {
typedef struct lfs_emubd {
// array of copy-on-write blocks
lfs2_emubd_block_t **blocks;
lfs_emubd_block_t **blocks;
// some other test state
lfs2_emubd_io_t readed;
lfs2_emubd_io_t proged;
lfs2_emubd_io_t erased;
lfs2_emubd_powercycles_t power_cycles;
lfs2_ssize_t ooo_block;
lfs2_emubd_block_t *ooo_data;
lfs2_emubd_disk_t *disk;
lfs_emubd_io_t readed;
lfs_emubd_io_t proged;
lfs_emubd_io_t erased;
lfs_emubd_powercycles_t power_cycles;
lfs_emubd_disk_t *disk;
const struct lfs2_emubd_config *cfg;
} lfs2_emubd_t;
const struct lfs_emubd_config *cfg;
} lfs_emubd_t;
/// Block device API ///
// Create an emulating block device using the geometry in lfs2_config
int lfs2_emubd_create(const struct lfs2_config *cfg,
const struct lfs2_emubd_config *bdcfg);
// Create an emulating block device using the geometry in lfs_config
int lfs_emubd_create(const struct lfs_config *cfg,
const struct lfs_emubd_config *bdcfg);
// Clean up memory associated with block device
int lfs2_emubd_destroy(const struct lfs2_config *cfg);
int lfs_emubd_destroy(const struct lfs_config *cfg);
// Read a block
int lfs2_emubd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size);
int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs2_emubd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size);
int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs2_emubd_erase(const struct lfs2_config *cfg, lfs2_block_t block);
int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block);
// Sync the block device
int lfs2_emubd_sync(const struct lfs2_config *cfg);
int lfs_emubd_sync(const struct lfs_config *cfg);
/// Additional extended API for driving test features ///
// A CRC of a block for debugging purposes
int lfs2_emubd_crc(const struct lfs2_config *cfg,
lfs2_block_t block, uint32_t *crc);
int lfs_emubd_crc(const struct lfs_config *cfg,
lfs_block_t block, uint32_t *crc);
// A CRC of the entire block device for debugging purposes
int lfs2_emubd_bdcrc(const struct lfs2_config *cfg, uint32_t *crc);
int lfs_emubd_bdcrc(const struct lfs_config *cfg, uint32_t *crc);
// Get total amount of bytes read
lfs2_emubd_sio_t lfs2_emubd_readed(const struct lfs2_config *cfg);
lfs_emubd_sio_t lfs_emubd_readed(const struct lfs_config *cfg);
// Get total amount of bytes programmed
lfs2_emubd_sio_t lfs2_emubd_proged(const struct lfs2_config *cfg);
lfs_emubd_sio_t lfs_emubd_proged(const struct lfs_config *cfg);
// Get total amount of bytes erased
lfs2_emubd_sio_t lfs2_emubd_erased(const struct lfs2_config *cfg);
lfs_emubd_sio_t lfs_emubd_erased(const struct lfs_config *cfg);
// Manually set amount of bytes read
int lfs2_emubd_setreaded(const struct lfs2_config *cfg, lfs2_emubd_io_t readed);
int lfs_emubd_setreaded(const struct lfs_config *cfg, lfs_emubd_io_t readed);
// Manually set amount of bytes programmed
int lfs2_emubd_setproged(const struct lfs2_config *cfg, lfs2_emubd_io_t proged);
int lfs_emubd_setproged(const struct lfs_config *cfg, lfs_emubd_io_t proged);
// Manually set amount of bytes erased
int lfs2_emubd_seterased(const struct lfs2_config *cfg, lfs2_emubd_io_t erased);
int lfs_emubd_seterased(const struct lfs_config *cfg, lfs_emubd_io_t erased);
// Get simulated wear on a given block
lfs2_emubd_swear_t lfs2_emubd_wear(const struct lfs2_config *cfg,
lfs2_block_t block);
lfs_emubd_swear_t lfs_emubd_wear(const struct lfs_config *cfg,
lfs_block_t block);
// Manually set simulated wear on a given block
int lfs2_emubd_setwear(const struct lfs2_config *cfg,
lfs2_block_t block, lfs2_emubd_wear_t wear);
int lfs_emubd_setwear(const struct lfs_config *cfg,
lfs_block_t block, lfs_emubd_wear_t wear);
// Get the remaining power-cycles
lfs2_emubd_spowercycles_t lfs2_emubd_powercycles(
const struct lfs2_config *cfg);
lfs_emubd_spowercycles_t lfs_emubd_powercycles(
const struct lfs_config *cfg);
// Manually set the remaining power-cycles
int lfs2_emubd_setpowercycles(const struct lfs2_config *cfg,
lfs2_emubd_powercycles_t power_cycles);
int lfs_emubd_setpowercycles(const struct lfs_config *cfg,
lfs_emubd_powercycles_t power_cycles);
// Create a copy-on-write copy of the state of this block device
int lfs2_emubd_copy(const struct lfs2_config *cfg, lfs2_emubd_t *copy);
int lfs_emubd_copy(const struct lfs_config *cfg, lfs_emubd_t *copy);
#ifdef __cplusplus

View File

@@ -5,7 +5,7 @@
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "bd/lfs2_filebd.h"
#include "bd/lfs_filebd.h"
#include <fcntl.h>
#include <unistd.h>
@@ -15,9 +15,9 @@
#include <windows.h>
#endif
int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path,
const struct lfs2_filebd_config *bdcfg) {
LFS2_FILEBD_TRACE("lfs2_filebd_create(%p {.context=%p, "
int lfs_filebd_create(const struct lfs_config *cfg, const char *path,
const struct lfs_filebd_config *bdcfg) {
LFS_FILEBD_TRACE("lfs_filebd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
"\"%s\", "
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
@@ -29,7 +29,7 @@ int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path,
(void*)bdcfg,
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
bdcfg->erase_count);
lfs2_filebd_t *bd = cfg->context;
lfs_filebd_t *bd = cfg->context;
bd->cfg = bdcfg;
// open file
@@ -41,39 +41,39 @@ int lfs2_filebd_create(const struct lfs2_config *cfg, const char *path,
if (bd->fd < 0) {
int err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_create -> %d", err);
LFS_FILEBD_TRACE("lfs_filebd_create -> %d", err);
return err;
}
LFS2_FILEBD_TRACE("lfs2_filebd_create -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_create -> %d", 0);
return 0;
}
int lfs2_filebd_destroy(const struct lfs2_config *cfg) {
LFS2_FILEBD_TRACE("lfs2_filebd_destroy(%p)", (void*)cfg);
lfs2_filebd_t *bd = cfg->context;
int lfs_filebd_destroy(const struct lfs_config *cfg) {
LFS_FILEBD_TRACE("lfs_filebd_destroy(%p)", (void*)cfg);
lfs_filebd_t *bd = cfg->context;
int err = close(bd->fd);
if (err < 0) {
err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_destroy -> %d", err);
LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", err);
return err;
}
LFS2_FILEBD_TRACE("lfs2_filebd_destroy -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_destroy -> %d", 0);
return 0;
}
int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, void *buffer, lfs2_size_t size) {
LFS2_FILEBD_TRACE("lfs2_filebd_read(%p, "
int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_FILEBD_TRACE("lfs_filebd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_filebd_t *bd = cfg->context;
lfs_filebd_t *bd = cfg->context;
// check if read is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS2_ASSERT(off % bd->cfg->read_size == 0);
LFS2_ASSERT(size % bd->cfg->read_size == 0);
LFS2_ASSERT(off+size <= bd->cfg->erase_size);
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(off+size <= bd->cfg->erase_size);
// zero for reproducibility (in case file is truncated)
memset(buffer, 0, size);
@@ -83,74 +83,74 @@ int lfs2_filebd_read(const struct lfs2_config *cfg, lfs2_block_t block,
(off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", err);
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err);
return err;
}
ssize_t res2 = read(bd->fd, buffer, size);
if (res2 < 0) {
int err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", err);
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", err);
return err;
}
LFS2_FILEBD_TRACE("lfs2_filebd_read -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_read -> %d", 0);
return 0;
}
int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
lfs2_off_t off, const void *buffer, lfs2_size_t size) {
LFS2_FILEBD_TRACE("lfs2_filebd_prog(%p, "
int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_FILEBD_TRACE("lfs_filebd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs2_filebd_t *bd = cfg->context;
lfs_filebd_t *bd = cfg->context;
// check if write is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS2_ASSERT(off % bd->cfg->prog_size == 0);
LFS2_ASSERT(size % bd->cfg->prog_size == 0);
LFS2_ASSERT(off+size <= bd->cfg->erase_size);
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(off+size <= bd->cfg->erase_size);
// program data
off_t res1 = lseek(bd->fd,
(off_t)block*bd->cfg->erase_size + (off_t)off, SEEK_SET);
if (res1 < 0) {
int err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err);
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
return err;
}
ssize_t res2 = write(bd->fd, buffer, size);
if (res2 < 0) {
int err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", err);
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", err);
return err;
}
LFS2_FILEBD_TRACE("lfs2_filebd_prog -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_prog -> %d", 0);
return 0;
}
int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
LFS2_FILEBD_TRACE("lfs2_filebd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
(void*)cfg, block, ((lfs2_filebd_t*)cfg->context)->cfg->erase_size);
lfs2_filebd_t *bd = cfg->context;
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block) {
LFS_FILEBD_TRACE("lfs_filebd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
(void*)cfg, block, ((lfs_file_t*)cfg->context)->cfg->erase_size);
lfs_filebd_t *bd = cfg->context;
// check if erase is valid
LFS2_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(block < bd->cfg->erase_count);
// erase is a noop
(void)block;
LFS2_FILEBD_TRACE("lfs2_filebd_erase -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_erase -> %d", 0);
return 0;
}
int lfs2_filebd_sync(const struct lfs2_config *cfg) {
LFS2_FILEBD_TRACE("lfs2_filebd_sync(%p)", (void*)cfg);
int lfs_filebd_sync(const struct lfs_config *cfg) {
LFS_FILEBD_TRACE("lfs_filebd_sync(%p)", (void*)cfg);
// file sync
lfs2_filebd_t *bd = cfg->context;
lfs_filebd_t *bd = cfg->context;
#ifdef _WIN32
int err = FlushFileBuffers((HANDLE) _get_osfhandle(bd->fd)) ? 0 : -1;
#else
@@ -158,10 +158,10 @@ int lfs2_filebd_sync(const struct lfs2_config *cfg) {
#endif
if (err) {
err = -errno;
LFS2_FILEBD_TRACE("lfs2_filebd_sync -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0);
return err;
}
LFS2_FILEBD_TRACE("lfs2_filebd_sync -> %d", 0);
LFS_FILEBD_TRACE("lfs_filebd_sync -> %d", 0);
return 0;
}

82
bd/lfs_filebd.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* Block device emulated in a file
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS_FILEBD_H
#define LFS_FILEBD_H
#include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifndef LFS_FILEBD_TRACE
#ifdef LFS_FILEBD_YES_TRACE
#define LFS_FILEBD_TRACE(...) LFS_TRACE(__VA_ARGS__)
#else
#define LFS_FILEBD_TRACE(...)
#endif
#endif
// filebd config
struct lfs_filebd_config {
// Minimum size of a read operation in bytes.
lfs_size_t read_size;
// Minimum size of a program operation in bytes.
lfs_size_t prog_size;
// Size of an erase operation in bytes.
lfs_size_t erase_size;
// Number of erase blocks on the device.
lfs_size_t erase_count;
};
// filebd state
typedef struct lfs_filebd {
int fd;
const struct lfs_filebd_config *cfg;
} lfs_filebd_t;
// Create a file block device
int lfs_filebd_create(const struct lfs_config *cfg, const char *path,
const struct lfs_filebd_config *bdcfg);
// Clean up memory associated with block device
int lfs_filebd_destroy(const struct lfs_config *cfg);
// Read a block
int lfs_filebd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs_filebd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs_filebd_erase(const struct lfs_config *cfg, lfs_block_t block);
// Sync the block device
int lfs_filebd_sync(const struct lfs_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

118
bd/lfs_rambd.c Normal file
View File

@@ -0,0 +1,118 @@
/*
* Block device emulated in RAM
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "bd/lfs_rambd.h"
int lfs_rambd_create(const struct lfs_config *cfg,
const struct lfs_rambd_config *bdcfg) {
LFS_RAMBD_TRACE("lfs_rambd_create(%p {.context=%p, "
".read=%p, .prog=%p, .erase=%p, .sync=%p}, "
"%p {.read_size=%"PRIu32", .prog_size=%"PRIu32", "
".erase_size=%"PRIu32", .erase_count=%"PRIu32", "
".buffer=%p})",
(void*)cfg, cfg->context,
(void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog,
(void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync,
(void*)bdcfg,
bdcfg->read_size, bdcfg->prog_size, bdcfg->erase_size,
bdcfg->erase_count, bdcfg->buffer);
lfs_rambd_t *bd = cfg->context;
bd->cfg = bdcfg;
// allocate buffer?
if (bd->cfg->buffer) {
bd->buffer = bd->cfg->buffer;
} else {
bd->buffer = lfs_malloc(bd->cfg->erase_size * bd->cfg->erase_count);
if (!bd->buffer) {
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", LFS_ERR_NOMEM);
return LFS_ERR_NOMEM;
}
}
// zero for reproducibility
memset(bd->buffer, 0, bd->cfg->erase_size * bd->cfg->erase_count);
LFS_RAMBD_TRACE("lfs_rambd_create -> %d", 0);
return 0;
}
int lfs_rambd_destroy(const struct lfs_config *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_destroy(%p)", (void*)cfg);
// clean up memory
lfs_rambd_t *bd = cfg->context;
if (!bd->cfg->buffer) {
lfs_free(bd->buffer);
}
LFS_RAMBD_TRACE("lfs_rambd_destroy -> %d", 0);
return 0;
}
int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size) {
LFS_RAMBD_TRACE("lfs_rambd_read(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs_rambd_t *bd = cfg->context;
// check if read is valid
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(off % bd->cfg->read_size == 0);
LFS_ASSERT(size % bd->cfg->read_size == 0);
LFS_ASSERT(off+size <= bd->cfg->erase_size);
// read data
memcpy(buffer, &bd->buffer[block*bd->cfg->erase_size + off], size);
LFS_RAMBD_TRACE("lfs_rambd_read -> %d", 0);
return 0;
}
int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size) {
LFS_RAMBD_TRACE("lfs_rambd_prog(%p, "
"0x%"PRIx32", %"PRIu32", %p, %"PRIu32")",
(void*)cfg, block, off, buffer, size);
lfs_rambd_t *bd = cfg->context;
// check if write is valid
LFS_ASSERT(block < bd->cfg->erase_count);
LFS_ASSERT(off % bd->cfg->prog_size == 0);
LFS_ASSERT(size % bd->cfg->prog_size == 0);
LFS_ASSERT(off+size <= bd->cfg->erase_size);
// program data
memcpy(&bd->buffer[block*bd->cfg->erase_size + off], buffer, size);
LFS_RAMBD_TRACE("lfs_rambd_prog -> %d", 0);
return 0;
}
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block) {
LFS_RAMBD_TRACE("lfs_rambd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
(void*)cfg, block, ((lfs_rambd_t*)cfg->context)->cfg->erase_size);
lfs_rambd_t *bd = cfg->context;
// check if erase is valid
LFS_ASSERT(block < bd->cfg->erase_count);
// erase is a noop
(void)block;
LFS_RAMBD_TRACE("lfs_rambd_erase -> %d", 0);
return 0;
}
int lfs_rambd_sync(const struct lfs_config *cfg) {
LFS_RAMBD_TRACE("lfs_rambd_sync(%p)", (void*)cfg);
// sync is a noop
(void)cfg;
LFS_RAMBD_TRACE("lfs_rambd_sync -> %d", 0);
return 0;
}

85
bd/lfs_rambd.h Normal file
View File

@@ -0,0 +1,85 @@
/*
* Block device emulated in RAM
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS_RAMBD_H
#define LFS_RAMBD_H
#include "lfs.h"
#include "lfs_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
// Block device specific tracing
#ifndef LFS_RAMBD_TRACE
#ifdef LFS_RAMBD_YES_TRACE
#define LFS_RAMBD_TRACE(...) LFS_TRACE(__VA_ARGS__)
#else
#define LFS_RAMBD_TRACE(...)
#endif
#endif
// rambd config
struct lfs_rambd_config {
// Minimum size of a read operation in bytes.
lfs_size_t read_size;
// Minimum size of a program operation in bytes.
lfs_size_t prog_size;
// Size of an erase operation in bytes.
lfs_size_t erase_size;
// Number of erase blocks on the device.
lfs_size_t erase_count;
// Optional statically allocated buffer for the block device.
void *buffer;
};
// rambd state
typedef struct lfs_rambd {
uint8_t *buffer;
const struct lfs_rambd_config *cfg;
} lfs_rambd_t;
// Create a RAM block device
int lfs_rambd_create(const struct lfs_config *cfg,
const struct lfs_rambd_config *bdcfg);
// Clean up memory associated with block device
int lfs_rambd_destroy(const struct lfs_config *cfg);
// Read a block
int lfs_rambd_read(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, void *buffer, lfs_size_t size);
// Program a block
//
// The block must have previously been erased.
int lfs_rambd_prog(const struct lfs_config *cfg, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size);
// Erase a block
//
// A block must be erased before being programmed. The
// state of an erased block is undefined.
int lfs_rambd_erase(const struct lfs_config *cfg, lfs_block_t block);
// Sync the block device
int lfs_rambd_sync(const struct lfs_config *cfg);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -7,55 +7,55 @@ defines.N = 1024
defines.FILE_SIZE = 8
defines.CHUNK_SIZE = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// first create the files
char name[256];
uint8_t buffer[CHUNK_SIZE];
for (lfs2_size_t i = 0; i < N; i++) {
for (lfs_size_t i = 0; i < N; i++) {
sprintf(name, "file%08x", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, name,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, name,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t file_prng = i;
for (lfs2_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs2_size_t k = 0; k < CHUNK_SIZE; k++) {
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) {
buffer[k] = BENCH_PRNG(&file_prng);
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
// then read the files
BENCH_START();
uint32_t prng = 42;
for (lfs2_size_t i = 0; i < N; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < N; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (N-1-i)
: BENCH_PRNG(&prng) % N;
sprintf(name, "file%08x", i_);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, name, LFS2_O_RDONLY) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
uint32_t file_prng = i_;
for (lfs2_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
lfs2_file_read(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
for (lfs2_size_t k = 0; k < CHUNK_SIZE; k++) {
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
lfs_file_read(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) {
assert(buffer[k] == BENCH_PRNG(&file_prng));
}
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_dir_creat]
@@ -67,37 +67,37 @@ defines.N = 1024
defines.FILE_SIZE = 8
defines.CHUNK_SIZE = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
BENCH_START();
uint32_t prng = 42;
char name[256];
uint8_t buffer[CHUNK_SIZE];
for (lfs2_size_t i = 0; i < N; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < N; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (N-1-i)
: BENCH_PRNG(&prng) % N;
sprintf(name, "file%08x", i_);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, name,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, name,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint32_t file_prng = i_;
for (lfs2_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs2_size_t k = 0; k < CHUNK_SIZE; k++) {
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) {
buffer[k] = BENCH_PRNG(&file_prng);
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_dir_remove]
@@ -109,45 +109,45 @@ defines.N = 1024
defines.FILE_SIZE = 8
defines.CHUNK_SIZE = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// first create the files
char name[256];
uint8_t buffer[CHUNK_SIZE];
for (lfs2_size_t i = 0; i < N; i++) {
for (lfs_size_t i = 0; i < N; i++) {
sprintf(name, "file%08x", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, name,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, name,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t file_prng = i;
for (lfs2_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs2_size_t k = 0; k < CHUNK_SIZE; k++) {
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) {
buffer[k] = BENCH_PRNG(&file_prng);
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
// then remove the files
BENCH_START();
uint32_t prng = 42;
for (lfs2_size_t i = 0; i < N; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < N; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (N-1-i)
: BENCH_PRNG(&prng) % N;
sprintf(name, "file%08x", i_);
int err = lfs2_remove(&lfs2, name);
assert(!err || err == LFS2_ERR_NOENT);
int err = lfs_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOENT);
}
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_dir_read]
@@ -155,52 +155,52 @@ defines.N = 1024
defines.FILE_SIZE = 8
defines.CHUNK_SIZE = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// first create the files
char name[256];
uint8_t buffer[CHUNK_SIZE];
for (lfs2_size_t i = 0; i < N; i++) {
for (lfs_size_t i = 0; i < N; i++) {
sprintf(name, "file%08x", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, name,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, name,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t file_prng = i;
for (lfs2_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs2_size_t k = 0; k < CHUNK_SIZE; k++) {
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) {
buffer[k] = BENCH_PRNG(&file_prng);
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
// then read the directory
BENCH_START();
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0;
struct lfs2_info info;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS2_TYPE_DIR);
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS2_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
sprintf(name, "file%08x", i);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS2_TYPE_REG);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
assert(strcmp(info.name, name) == 0);
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_dir_mkdir]
@@ -210,26 +210,26 @@ code = '''
defines.ORDER = [0, 1, 2]
defines.N = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
BENCH_START();
uint32_t prng = 42;
char name[256];
for (lfs2_size_t i = 0; i < N; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < N; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (N-1-i)
: BENCH_PRNG(&prng) % N;
printf("hm %d\n", i);
sprintf(name, "dir%08x", i_);
int err = lfs2_mkdir(&lfs2, name);
assert(!err || err == LFS2_ERR_EXIST);
int err = lfs_mkdir(&lfs, name);
assert(!err || err == LFS_ERR_EXIST);
}
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_dir_rmdir]
@@ -239,32 +239,32 @@ code = '''
defines.ORDER = [0, 1, 2]
defines.N = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// first create the dirs
char name[256];
for (lfs2_size_t i = 0; i < N; i++) {
for (lfs_size_t i = 0; i < N; i++) {
sprintf(name, "dir%08x", i);
lfs2_mkdir(&lfs2, name) => 0;
lfs_mkdir(&lfs, name) => 0;
}
// then remove the dirs
BENCH_START();
uint32_t prng = 42;
for (lfs2_size_t i = 0; i < N; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < N; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (N-1-i)
: BENCH_PRNG(&prng) % N;
sprintf(name, "dir%08x", i_);
int err = lfs2_remove(&lfs2, name);
assert(!err || err == LFS2_ERR_NOENT);
int err = lfs_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOENT);
}
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -6,51 +6,51 @@ defines.ORDER = [0, 1, 2]
defines.SIZE = '128*1024'
defines.CHUNK_SIZE = 64
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_size_t chunks = (SIZE+CHUNK_SIZE-1)/CHUNK_SIZE;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_size_t chunks = (SIZE+CHUNK_SIZE-1)/CHUNK_SIZE;
// first write the file
lfs2_file_t file;
lfs_file_t file;
uint8_t buffer[CHUNK_SIZE];
lfs2_file_open(&lfs2, &file, "file",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
for (lfs2_size_t i = 0; i < chunks; i++) {
lfs_file_open(&lfs, &file, "file",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
for (lfs_size_t i = 0; i < chunks; i++) {
uint32_t chunk_prng = i;
for (lfs2_size_t j = 0; j < CHUNK_SIZE; j++) {
for (lfs_size_t j = 0; j < CHUNK_SIZE; j++) {
buffer[j] = BENCH_PRNG(&chunk_prng);
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_close(&lfs, &file) => 0;
// then read the file
BENCH_START();
lfs2_file_open(&lfs2, &file, "file", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "file", LFS_O_RDONLY) => 0;
uint32_t prng = 42;
for (lfs2_size_t i = 0; i < chunks; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < chunks; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (chunks-1-i)
: BENCH_PRNG(&prng) % chunks;
lfs2_file_seek(&lfs2, &file, i_*CHUNK_SIZE, LFS2_SEEK_SET)
lfs_file_seek(&lfs, &file, i_*CHUNK_SIZE, LFS_SEEK_SET)
=> i_*CHUNK_SIZE;
lfs2_file_read(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_read(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
uint32_t chunk_prng = i_;
for (lfs2_size_t j = 0; j < CHUNK_SIZE; j++) {
for (lfs_size_t j = 0; j < CHUNK_SIZE; j++) {
assert(buffer[j] == BENCH_PRNG(&chunk_prng));
}
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_file_write]
@@ -61,35 +61,35 @@ defines.ORDER = [0, 1, 2]
defines.SIZE = '128*1024'
defines.CHUNK_SIZE = 64
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_size_t chunks = (SIZE+CHUNK_SIZE-1)/CHUNK_SIZE;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_size_t chunks = (SIZE+CHUNK_SIZE-1)/CHUNK_SIZE;
BENCH_START();
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "file",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "file",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint8_t buffer[CHUNK_SIZE];
uint32_t prng = 42;
for (lfs2_size_t i = 0; i < chunks; i++) {
lfs2_off_t i_
for (lfs_size_t i = 0; i < chunks; i++) {
lfs_off_t i_
= (ORDER == 0) ? i
: (ORDER == 1) ? (chunks-1-i)
: BENCH_PRNG(&prng) % chunks;
uint32_t chunk_prng = i_;
for (lfs2_size_t j = 0; j < CHUNK_SIZE; j++) {
for (lfs_size_t j = 0; j < CHUNK_SIZE; j++) {
buffer[j] = BENCH_PRNG(&chunk_prng);
}
lfs2_file_seek(&lfs2, &file, i_*CHUNK_SIZE, LFS2_SEEK_SET)
lfs_file_seek(&lfs, &file, i_*CHUNK_SIZE, LFS_SEEK_SET)
=> i_*CHUNK_SIZE;
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -4,53 +4,53 @@ defines.N = [0, 1024]
defines.FILE_SIZE = 8
defines.CHUNK_SIZE = 8
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create files?
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
char name[256];
uint8_t buffer[CHUNK_SIZE];
for (lfs2_size_t i = 0; i < N; i++) {
for (lfs_size_t i = 0; i < N; i++) {
sprintf(name, "file%08x", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, name,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, name,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
for (lfs2_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs2_size_t k = 0; k < CHUNK_SIZE; k++) {
for (lfs_size_t j = 0; j < FILE_SIZE; j += CHUNK_SIZE) {
for (lfs_size_t k = 0; k < CHUNK_SIZE; k++) {
buffer[k] = i+j+k;
}
lfs2_file_write(&lfs2, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
lfs_file_write(&lfs, &file, buffer, CHUNK_SIZE) => CHUNK_SIZE;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
BENCH_START();
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
BENCH_STOP();
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.bench_superblocks_missing]
code = '''
lfs2_t lfs2;
lfs_t lfs;
BENCH_START();
int err = lfs2_mount(&lfs2, cfg);
int err = lfs_mount(&lfs, cfg);
assert(err != 0);
BENCH_STOP();
'''
[cases.bench_superblocks_format]
code = '''
lfs2_t lfs2;
lfs_t lfs;
BENCH_START();
lfs2_format(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
BENCH_STOP();
'''

6333
lfs.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6549
lfs2.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,18 @@
/*
* lfs2 util functions
* lfs util functions
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "lfs2_util.h"
#include "lfs_util.h"
// Only compile if user does not provide custom config
#ifndef LFS2_CONFIG
#ifndef LFS_CONFIG
// If user provides their own CRC impl we don't need this
#ifndef LFS2_CRC
// Software CRC implementation with small lookup table
uint32_t lfs2_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] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
@@ -31,7 +29,6 @@ uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
return crc;
}
#endif
#endif

View File

@@ -1,59 +1,41 @@
/*
* lfs2 utility functions
* lfs utility functions
*
* Copyright (c) 2022, The littlefs authors.
* Copyright (c) 2017, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef LFS2_UTIL_H
#define LFS2_UTIL_H
#ifndef LFS_UTIL_H
#define LFS_UTIL_H
#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
#define LFS2_STRINGIZE2(x) #x
// Users can override lfs2_util.h with their own configuration by defining
// LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h).
// Users can override lfs_util.h with their own configuration by defining
// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
//
// If LFS2_CONFIG is used, none of the default utils will be emitted and must be
// provided by the config file. To start, I would suggest copying lfs2_util.h
// If LFS_CONFIG is used, none of the default utils will be emitted and must be
// provided by the config file. To start, I would suggest copying lfs_util.h
// and modifying as needed.
#ifdef LFS2_CONFIG
#include LFS2_STRINGIZE(LFS2_CONFIG)
#ifdef LFS_CONFIG
#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
#define LFS_STRINGIZE2(x) #x
#include LFS_STRINGIZE(LFS_CONFIG)
#else
// Alternatively, users can provide a header file which defines
// macros and other things consumed by littlefs.
//
// For example, provide my_defines.h, which contains
// something like:
//
// #include <stddef.h>
// extern void *my_malloc(size_t sz);
// #define LFS2_MALLOC(sz) my_malloc(sz)
//
// And build littlefs with the header by defining LFS2_DEFINES.
// (-DLFS2_DEFINES=my_defines.h)
#ifdef LFS2_DEFINES
#include LFS2_STRINGIZE(LFS2_DEFINES)
#endif
// System includes
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#ifndef LFS2_NO_MALLOC
#ifndef LFS_NO_MALLOC
#include <stdlib.h>
#endif
#ifndef LFS2_NO_ASSERT
#ifndef LFS_NO_ASSERT
#include <assert.h>
#endif
#if !defined(LFS2_NO_DEBUG) || \
!defined(LFS2_NO_WARN) || \
!defined(LFS2_NO_ERROR) || \
defined(LFS2_YES_TRACE)
#if !defined(LFS_NO_DEBUG) || \
!defined(LFS_NO_WARN) || \
!defined(LFS_NO_ERROR) || \
defined(LFS_YES_TRACE)
#include <stdio.h>
#endif
@@ -68,81 +50,81 @@ extern "C"
// code footprint
// Logging functions
#ifndef LFS2_TRACE
#ifdef LFS2_YES_TRACE
#define LFS2_TRACE_(fmt, ...) \
#ifndef LFS_TRACE
#ifdef LFS_YES_TRACE
#define LFS_TRACE_(fmt, ...) \
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
#else
#define LFS2_TRACE(...)
#define LFS_TRACE(...)
#endif
#endif
#ifndef LFS2_DEBUG
#ifndef LFS2_NO_DEBUG
#define LFS2_DEBUG_(fmt, ...) \
#ifndef LFS_DEBUG
#ifndef LFS_NO_DEBUG
#define LFS_DEBUG_(fmt, ...) \
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_DEBUG(...) LFS2_DEBUG_(__VA_ARGS__, "")
#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
#else
#define LFS2_DEBUG(...)
#define LFS_DEBUG(...)
#endif
#endif
#ifndef LFS2_WARN
#ifndef LFS2_NO_WARN
#define LFS2_WARN_(fmt, ...) \
#ifndef LFS_WARN
#ifndef LFS_NO_WARN
#define LFS_WARN_(fmt, ...) \
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_WARN(...) LFS2_WARN_(__VA_ARGS__, "")
#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
#else
#define LFS2_WARN(...)
#define LFS_WARN(...)
#endif
#endif
#ifndef LFS2_ERROR
#ifndef LFS2_NO_ERROR
#define LFS2_ERROR_(fmt, ...) \
#ifndef LFS_ERROR
#ifndef LFS_NO_ERROR
#define LFS_ERROR_(fmt, ...) \
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_ERROR(...) LFS2_ERROR_(__VA_ARGS__, "")
#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
#else
#define LFS2_ERROR(...)
#define LFS_ERROR(...)
#endif
#endif
// Runtime assertions
#ifndef LFS2_ASSERT
#ifndef LFS2_NO_ASSERT
#define LFS2_ASSERT(test) assert(test)
#ifndef LFS_ASSERT
#ifndef LFS_NO_ASSERT
#define LFS_ASSERT(test) assert(test)
#else
#define LFS2_ASSERT(test)
#define LFS_ASSERT(test)
#endif
#endif
// Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS2_NO_INTRINSICS falls back to a more
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
// expensive basic C implementation for debugging purposes
// Min/max functions for unsigned 32-bit numbers
static inline uint32_t lfs2_max(uint32_t a, uint32_t b) {
static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b;
}
static inline uint32_t lfs2_min(uint32_t a, uint32_t b) {
static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
return (a < b) ? a : b;
}
// Align to nearest multiple of a size
static inline uint32_t lfs2_aligndown(uint32_t a, uint32_t alignment) {
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
return a - (a % alignment);
}
static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) {
return lfs2_aligndown(a + alignment-1, alignment);
static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
return lfs_aligndown(a + alignment-1, alignment);
}
// Find the smallest power of 2 greater than or equal to a
static inline uint32_t lfs2_npw2(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
static inline uint32_t lfs_npw2(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return 32 - __builtin_clz(a-1);
#else
uint32_t r = 0;
@@ -157,18 +139,18 @@ static inline uint32_t lfs2_npw2(uint32_t a) {
}
// Count the number of trailing binary zeros in a
// lfs2_ctz(0) may be undefined
static inline uint32_t lfs2_ctz(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && defined(__GNUC__)
// lfs_ctz(0) may be undefined
static inline uint32_t lfs_ctz(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
return __builtin_ctz(a);
#else
return lfs2_npw2((a & -a) + 1) - 1;
return lfs_npw2((a & -a) + 1) - 1;
#endif
}
// Count the number of binary ones in a
static inline uint32_t lfs2_popc(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
static inline uint32_t lfs_popc(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return __builtin_popcount(a);
#else
a = a - ((a >> 1) & 0x55555555);
@@ -179,36 +161,36 @@ static inline uint32_t lfs2_popc(uint32_t a) {
// Find the sequence comparison of a and b, this is the distance
// between a and b ignoring overflow
static inline int lfs2_scmp(uint32_t a, uint32_t b) {
static inline int lfs_scmp(uint32_t a, uint32_t b) {
return (int)(unsigned)(a - b);
}
// Convert between 32-bit little-endian and native order
static inline uint32_t lfs2_fromle32(uint32_t a) {
static inline uint32_t lfs_fromle32(uint32_t a) {
#if (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
return a;
#elif !defined(LFS2_NO_INTRINSICS) && ( \
#elif !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return __builtin_bswap32(a);
#else
return ((uint32_t)((uint8_t*)&a)[0] << 0) |
((uint32_t)((uint8_t*)&a)[1] << 8) |
((uint32_t)((uint8_t*)&a)[2] << 16) |
((uint32_t)((uint8_t*)&a)[3] << 24);
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8) |
(((uint8_t*)&a)[2] << 16) |
(((uint8_t*)&a)[3] << 24);
#endif
}
static inline uint32_t lfs2_tole32(uint32_t a) {
return lfs2_fromle32(a);
static inline uint32_t lfs_tole32(uint32_t a) {
return lfs_fromle32(a);
}
// Convert between 32-bit big-endian and native order
static inline uint32_t lfs2_frombe32(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && ( \
static inline uint32_t lfs_frombe32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \
(defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
@@ -218,34 +200,24 @@ static inline uint32_t lfs2_frombe32(uint32_t a) {
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return a;
#else
return ((uint32_t)((uint8_t*)&a)[0] << 24) |
((uint32_t)((uint8_t*)&a)[1] << 16) |
((uint32_t)((uint8_t*)&a)[2] << 8) |
((uint32_t)((uint8_t*)&a)[3] << 0);
return (((uint8_t*)&a)[0] << 24) |
(((uint8_t*)&a)[1] << 16) |
(((uint8_t*)&a)[2] << 8) |
(((uint8_t*)&a)[3] << 0);
#endif
}
static inline uint32_t lfs2_tobe32(uint32_t a) {
return lfs2_frombe32(a);
static inline uint32_t lfs_tobe32(uint32_t a) {
return lfs_frombe32(a);
}
// Calculate CRC-32 with polynomial = 0x04c11db7
#ifdef LFS2_CRC
static inline uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
return LFS2_CRC(crc, buffer, size);
}
#else
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size);
#endif
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
// Allocate memory, only used if buffers are not provided to littlefs
//
// littlefs current has no alignment requirements, as it only allocates
// byte-level buffers.
static inline void *lfs2_malloc(size_t size) {
#if defined(LFS2_MALLOC)
return LFS2_MALLOC(size);
#elif !defined(LFS2_NO_MALLOC)
// Note, memory must be 64-bit aligned
static inline void *lfs_malloc(size_t size) {
#ifndef LFS_NO_MALLOC
return malloc(size);
#else
(void)size;
@@ -254,10 +226,8 @@ static inline void *lfs2_malloc(size_t size) {
}
// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs2_free(void *p) {
#if defined(LFS2_FREE)
LFS2_FREE(p);
#elif !defined(LFS2_NO_MALLOC)
static inline void lfs_free(void *p) {
#ifndef LFS_NO_MALLOC
free(p);
#else
(void)p;

View File

@@ -9,7 +9,7 @@
#endif
#include "runners/bench_runner.h"
#include "bd/lfs2_emubd.h"
#include "bd/lfs_emubd.h"
#include <getopt.h>
#include <sys/types.h>
@@ -123,13 +123,8 @@ typedef struct bench_id {
// bench suites are linked into a custom ld section
#if defined(__APPLE__)
extern struct bench_suite __start__bench_suites __asm("section$start$__DATA$_bench_suites");
extern struct bench_suite __stop__bench_suites __asm("section$end$__DATA$_bench_suites");
#else
extern struct bench_suite __start__bench_suites;
extern struct bench_suite __stop__bench_suites;
#endif
const struct bench_suite *bench_suites = &__start__bench_suites;
#define BENCH_SUITE_COUNT \
@@ -302,11 +297,11 @@ void bench_define_suite(const struct bench_suite *suite) {
suite->define_names, suite->define_count};
// make sure our cache is large enough
if (lfs2_max(suite->define_count, BENCH_IMPLICIT_DEFINE_COUNT)
if (lfs_max(suite->define_count, BENCH_IMPLICIT_DEFINE_COUNT)
> bench_define_cache_count) {
// align to power of two to avoid any superlinear growth
size_t ncount = 1 << lfs2_npw2(
lfs2_max(suite->define_count, BENCH_IMPLICIT_DEFINE_COUNT));
size_t ncount = 1 << lfs_npw2(
lfs_max(suite->define_count, BENCH_IMPLICIT_DEFINE_COUNT));
bench_define_cache = realloc(bench_define_cache, ncount*sizeof(intmax_t));
bench_define_cache_mask = realloc(bench_define_cache_mask,
sizeof(unsigned)*(
@@ -322,14 +317,14 @@ void bench_define_suite(const struct bench_suite *suite) {
size_t permutations = 1;
for (size_t i = 0; i < bench_override_count; i++) {
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
BENCH_IMPLICIT_DEFINE_COUNT);
d++) {
// define name match?
const char *name = bench_define_name(d);
if (name && strcmp(name, bench_overrides[i].name) == 0) {
count = lfs2_max(count, d+1);
count = lfs_max(count, d+1);
permutations *= bench_overrides[i].permutations;
break;
}
@@ -341,7 +336,7 @@ void bench_define_suite(const struct bench_suite *suite) {
// make sure our override arrays are big enough
if (count * permutations > bench_override_define_capacity) {
// align to power of two to avoid any superlinear growth
size_t ncapacity = 1 << lfs2_npw2(count * permutations);
size_t ncapacity = 1 << lfs_npw2(count * permutations);
bench_override_defines = realloc(
bench_override_defines,
sizeof(bench_define_t)*ncapacity);
@@ -356,7 +351,7 @@ void bench_define_suite(const struct bench_suite *suite) {
size_t p = 1;
for (size_t i = 0; i < bench_override_count; i++) {
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
BENCH_IMPLICIT_DEFINE_COUNT);
d++) {
@@ -438,9 +433,9 @@ FILE *bench_trace_file = NULL;
uint32_t bench_trace_cycles = 0;
uint64_t bench_trace_time = 0;
uint64_t bench_trace_open_time = 0;
lfs2_emubd_sleep_t bench_read_sleep = 0.0;
lfs2_emubd_sleep_t bench_prog_sleep = 0.0;
lfs2_emubd_sleep_t bench_erase_sleep = 0.0;
lfs_emubd_sleep_t bench_read_sleep = 0.0;
lfs_emubd_sleep_t bench_prog_sleep = 0.0;
lfs_emubd_sleep_t bench_erase_sleep = 0.0;
// this determines both the backtrace buffer and the trace printf buffer, if
// trace ends up interleaved or truncated this may need to be increased
@@ -562,13 +557,13 @@ uint32_t bench_prng(uint32_t *state) {
// bench recording state
static struct lfs2_config *bench_cfg = NULL;
static lfs2_emubd_io_t bench_last_readed = 0;
static lfs2_emubd_io_t bench_last_proged = 0;
static lfs2_emubd_io_t bench_last_erased = 0;
lfs2_emubd_io_t bench_readed = 0;
lfs2_emubd_io_t bench_proged = 0;
lfs2_emubd_io_t bench_erased = 0;
static struct lfs_config *bench_cfg = NULL;
static lfs_emubd_io_t bench_last_readed = 0;
static lfs_emubd_io_t bench_last_proged = 0;
static lfs_emubd_io_t bench_last_erased = 0;
lfs_emubd_io_t bench_readed = 0;
lfs_emubd_io_t bench_proged = 0;
lfs_emubd_io_t bench_erased = 0;
void bench_reset(void) {
bench_readed = 0;
@@ -581,11 +576,11 @@ void bench_reset(void) {
void bench_start(void) {
assert(bench_cfg);
lfs2_emubd_sio_t readed = lfs2_emubd_readed(bench_cfg);
lfs_emubd_sio_t readed = lfs_emubd_readed(bench_cfg);
assert(readed >= 0);
lfs2_emubd_sio_t proged = lfs2_emubd_proged(bench_cfg);
lfs_emubd_sio_t proged = lfs_emubd_proged(bench_cfg);
assert(proged >= 0);
lfs2_emubd_sio_t erased = lfs2_emubd_erased(bench_cfg);
lfs_emubd_sio_t erased = lfs_emubd_erased(bench_cfg);
assert(erased >= 0);
bench_last_readed = readed;
@@ -595,11 +590,11 @@ void bench_start(void) {
void bench_stop(void) {
assert(bench_cfg);
lfs2_emubd_sio_t readed = lfs2_emubd_readed(bench_cfg);
lfs_emubd_sio_t readed = lfs_emubd_readed(bench_cfg);
assert(readed >= 0);
lfs2_emubd_sio_t proged = lfs2_emubd_proged(bench_cfg);
lfs_emubd_sio_t proged = lfs_emubd_proged(bench_cfg);
assert(proged >= 0);
lfs2_emubd_sio_t erased = lfs2_emubd_erased(bench_cfg);
lfs_emubd_sio_t erased = lfs_emubd_erased(bench_cfg);
assert(erased >= 0);
bench_readed += readed - bench_last_readed;
@@ -616,7 +611,7 @@ static void perm_printid(
// case[:permutation]
printf("%s:", case_->name);
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
BENCH_IMPLICIT_DEFINE_COUNT);
d++) {
@@ -648,7 +643,7 @@ bool bench_seen_insert(
// use the currently set defines
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
BENCH_IMPLICIT_DEFINE_COUNT);
d++) {
@@ -1076,7 +1071,7 @@ void perm_list_defines(
// collect defines
for (size_t d = 0;
d < lfs2_max(suite->define_count,
d < lfs_max(suite->define_count,
BENCH_IMPLICIT_DEFINE_COUNT);
d++) {
if (d < BENCH_IMPLICIT_DEFINE_COUNT
@@ -1096,7 +1091,7 @@ void perm_list_permutation_defines(
// collect permutation_defines
for (size_t d = 0;
d < lfs2_max(suite->define_count,
d < lfs_max(suite->define_count,
BENCH_IMPLICIT_DEFINE_COUNT);
d++) {
if (bench_define_ispermutation(d)) {
@@ -1311,14 +1306,14 @@ void perm_run(
}
// create block device and configuration
lfs2_emubd_t bd;
lfs_emubd_t bd;
struct lfs2_config cfg = {
struct lfs_config cfg = {
.context = &bd,
.read = lfs2_emubd_read,
.prog = lfs2_emubd_prog,
.erase = lfs2_emubd_erase,
.sync = lfs2_emubd_sync,
.read = lfs_emubd_read,
.prog = lfs_emubd_prog,
.erase = lfs_emubd_erase,
.sync = lfs_emubd_sync,
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.block_size = BLOCK_SIZE,
@@ -1326,12 +1321,9 @@ void perm_run(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.metadata_max = METADATA_MAX,
.inline_max = INLINE_MAX,
};
struct lfs2_emubd_config bdcfg = {
struct lfs_emubd_config bdcfg = {
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.erase_size = ERASE_SIZE,
@@ -1345,7 +1337,7 @@ void perm_run(
.erase_sleep = bench_erase_sleep,
};
int err = lfs2_emubd_create(&cfg, &bdcfg);
int err = lfs_emubd_create(&cfg, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1369,7 +1361,7 @@ void perm_run(
printf("\n");
// cleanup
err = lfs2_emubd_destroy(&cfg);
err = lfs_emubd_destroy(&cfg);
if (err) {
fprintf(stderr, "error: could not destroy block device: %d\n", err);
exit(-1);
@@ -1745,7 +1737,7 @@ invalid_define:
// comma-separated read/prog/erase/count
if (*optarg == '{') {
lfs2_size_t sizes[4];
lfs_size_t sizes[4];
size_t count = 0;
char *s = optarg + 1;
@@ -1794,7 +1786,7 @@ invalid_define:
// leb16-encoded read/prog/erase/count
if (*optarg == ':') {
lfs2_size_t sizes[4];
lfs_size_t sizes[4];
size_t count = 0;
char *s = optarg + 1;
@@ -2017,7 +2009,7 @@ getopt_done: ;
if (d >= define_count) {
// align to power of two to avoid any superlinear growth
size_t ncount = 1 << lfs2_npw2(d+1);
size_t ncount = 1 << lfs_npw2(d+1);
defines = realloc(defines,
ncount*sizeof(bench_define_t));
memset(defines+define_count, 0,

View File

@@ -8,16 +8,16 @@
#define BENCH_RUNNER_H
// override LFS2_TRACE
// override LFS_TRACE
void bench_trace(const char *fmt, ...);
#define LFS2_TRACE_(fmt, ...) \
#define LFS_TRACE_(fmt, ...) \
bench_trace("%s:%d:trace: " fmt "%s\n", \
__FILE__, \
__LINE__, \
__VA_ARGS__)
#define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#define LFS2_EMUBD_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
#define LFS_EMUBD_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
// provide BENCH_START/BENCH_STOP macros
void bench_start(void);
@@ -28,7 +28,7 @@ void bench_stop(void);
// note these are indirectly included in any generated files
#include "bd/lfs2_emubd.h"
#include "bd/lfs_emubd.h"
#include <stdio.h>
// give source a chance to define feature macros
@@ -37,7 +37,7 @@ void bench_stop(void);
// generated bench configurations
struct lfs2_config;
struct lfs_config;
enum bench_flags {
BENCH_REENTRANT = 0x1,
@@ -58,7 +58,7 @@ struct bench_case {
const bench_define_t *defines;
bool (*filter)(void);
void (*run)(struct lfs2_config *cfg);
void (*run)(struct lfs_config *cfg);
};
struct bench_suite {
@@ -95,14 +95,11 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7
#define COMPACT_THRESH_i 8
#define METADATA_MAX_i 9
#define INLINE_MAX_i 10
#define BLOCK_CYCLES_i 11
#define ERASE_VALUE_i 12
#define ERASE_CYCLES_i 13
#define BADBLOCK_BEHAVIOR_i 14
#define POWERLOSS_BEHAVIOR_i 15
#define BLOCK_CYCLES_i 8
#define ERASE_VALUE_i 9
#define ERASE_CYCLES_i 10
#define BADBLOCK_BEHAVIOR_i 11
#define POWERLOSS_BEHAVIOR_i 12
#define READ_SIZE bench_define(READ_SIZE_i)
#define PROG_SIZE bench_define(PROG_SIZE_i)
@@ -112,9 +109,6 @@ intmax_t bench_define(size_t define);
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i)
#define CACHE_SIZE bench_define(CACHE_SIZE_i)
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
#define COMPACT_THRESH bench_define(COMPACT_THRESH_i)
#define METADATA_MAX bench_define(METADATA_MAX_i)
#define INLINE_MAX bench_define(INLINE_MAX_i)
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
#define ERASE_VALUE bench_define(ERASE_VALUE_i)
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i)
@@ -127,20 +121,17 @@ intmax_t bench_define(size_t define);
BENCH_DEF(ERASE_SIZE, 0) \
BENCH_DEF(ERASE_COUNT, (1024*1024)/BLOCK_SIZE) \
BENCH_DEF(BLOCK_SIZE, ERASE_SIZE) \
BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs2_max(BLOCK_SIZE/ERASE_SIZE,1))\
BENCH_DEF(CACHE_SIZE, lfs2_max(64,lfs2_max(READ_SIZE,PROG_SIZE))) \
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(LOOKAHEAD_SIZE, 16) \
BENCH_DEF(COMPACT_THRESH, 0) \
BENCH_DEF(METADATA_MAX, 0) \
BENCH_DEF(INLINE_MAX, 0) \
BENCH_DEF(BLOCK_CYCLES, -1) \
BENCH_DEF(ERASE_VALUE, 0xff) \
BENCH_DEF(ERASE_CYCLES, 0) \
BENCH_DEF(BADBLOCK_BEHAVIOR, LFS2_EMUBD_BADBLOCK_PROGERROR) \
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS2_EMUBD_POWERLOSS_NOOP)
BENCH_DEF(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR) \
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
#define BENCH_GEOMETRY_DEFINE_COUNT 4
#define BENCH_IMPLICIT_DEFINE_COUNT 16
#define BENCH_IMPLICIT_DEFINE_COUNT 13
#endif

View File

@@ -9,7 +9,7 @@
#endif
#include "runners/test_runner.h"
#include "bd/lfs2_emubd.h"
#include "bd/lfs_emubd.h"
#include <getopt.h>
#include <sys/types.h>
@@ -118,11 +118,11 @@ typedef struct test_geometry {
typedef struct test_powerloss {
const char *name;
void (*run)(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_);
const lfs2_emubd_powercycles_t *cycles;
const lfs_emubd_powercycles_t *cycles;
size_t cycle_count;
} test_powerloss_t;
@@ -130,19 +130,14 @@ typedef struct test_id {
const char *name;
const test_define_t *defines;
size_t define_count;
const lfs2_emubd_powercycles_t *cycles;
const lfs_emubd_powercycles_t *cycles;
size_t cycle_count;
} test_id_t;
// test suites are linked into a custom ld section
#if defined(__APPLE__)
extern struct test_suite __start__test_suites __asm("section$start$__DATA$_test_suites");
extern struct test_suite __stop__test_suites __asm("section$end$__DATA$_test_suites");
#else
extern struct test_suite __start__test_suites;
extern struct test_suite __stop__test_suites;
#endif
const struct test_suite *test_suites = &__start__test_suites;
#define TEST_SUITE_COUNT \
@@ -315,11 +310,11 @@ void test_define_suite(const struct test_suite *suite) {
suite->define_names, suite->define_count};
// make sure our cache is large enough
if (lfs2_max(suite->define_count, TEST_IMPLICIT_DEFINE_COUNT)
if (lfs_max(suite->define_count, TEST_IMPLICIT_DEFINE_COUNT)
> test_define_cache_count) {
// align to power of two to avoid any superlinear growth
size_t ncount = 1 << lfs2_npw2(
lfs2_max(suite->define_count, TEST_IMPLICIT_DEFINE_COUNT));
size_t ncount = 1 << lfs_npw2(
lfs_max(suite->define_count, TEST_IMPLICIT_DEFINE_COUNT));
test_define_cache = realloc(test_define_cache, ncount*sizeof(intmax_t));
test_define_cache_mask = realloc(test_define_cache_mask,
sizeof(unsigned)*(
@@ -335,14 +330,14 @@ void test_define_suite(const struct test_suite *suite) {
size_t permutations = 1;
for (size_t i = 0; i < test_override_count; i++) {
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
TEST_IMPLICIT_DEFINE_COUNT);
d++) {
// define name match?
const char *name = test_define_name(d);
if (name && strcmp(name, test_overrides[i].name) == 0) {
count = lfs2_max(count, d+1);
count = lfs_max(count, d+1);
permutations *= test_overrides[i].permutations;
break;
}
@@ -354,7 +349,7 @@ void test_define_suite(const struct test_suite *suite) {
// make sure our override arrays are big enough
if (count * permutations > test_override_define_capacity) {
// align to power of two to avoid any superlinear growth
size_t ncapacity = 1 << lfs2_npw2(count * permutations);
size_t ncapacity = 1 << lfs_npw2(count * permutations);
test_override_defines = realloc(
test_override_defines,
sizeof(test_define_t)*ncapacity);
@@ -369,7 +364,7 @@ void test_define_suite(const struct test_suite *suite) {
size_t p = 1;
for (size_t i = 0; i < test_override_count; i++) {
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
TEST_IMPLICIT_DEFINE_COUNT);
d++) {
@@ -454,9 +449,9 @@ FILE *test_trace_file = NULL;
uint32_t test_trace_cycles = 0;
uint64_t test_trace_time = 0;
uint64_t test_trace_open_time = 0;
lfs2_emubd_sleep_t test_read_sleep = 0.0;
lfs2_emubd_sleep_t test_prog_sleep = 0.0;
lfs2_emubd_sleep_t test_erase_sleep = 0.0;
lfs_emubd_sleep_t test_read_sleep = 0.0;
lfs_emubd_sleep_t test_prog_sleep = 0.0;
lfs_emubd_sleep_t test_erase_sleep = 0.0;
// this determines both the backtrace buffer and the trace printf buffer, if
// trace ends up interleaved or truncated this may need to be increased
@@ -581,13 +576,13 @@ uint32_t test_prng(uint32_t *state) {
static void perm_printid(
const struct test_suite *suite,
const struct test_case *case_,
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count) {
(void)suite;
// case[:permutation[:powercycles]]
printf("%s:", case_->name);
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
TEST_IMPLICIT_DEFINE_COUNT);
d++) {
@@ -628,7 +623,7 @@ bool test_seen_insert(
// use the currently set defines
for (size_t d = 0;
d < lfs2_max(
d < lfs_max(
suite->define_count,
TEST_IMPLICIT_DEFINE_COUNT);
d++) {
@@ -670,12 +665,12 @@ void test_seen_cleanup(test_seen_t *seen) {
}
static void run_powerloss_none(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_);
static void run_powerloss_cycles(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_);
@@ -686,7 +681,7 @@ static void case_forperm(
const struct test_case *case_,
const test_define_t *defines,
size_t define_count,
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
void (*cb)(
void *data,
@@ -1111,7 +1106,7 @@ void perm_list_defines(
// collect defines
for (size_t d = 0;
d < lfs2_max(suite->define_count,
d < lfs_max(suite->define_count,
TEST_IMPLICIT_DEFINE_COUNT);
d++) {
if (d < TEST_IMPLICIT_DEFINE_COUNT
@@ -1133,7 +1128,7 @@ void perm_list_permutation_defines(
// collect permutation_defines
for (size_t d = 0;
d < lfs2_max(suite->define_count,
d < lfs_max(suite->define_count,
TEST_IMPLICIT_DEFINE_COUNT);
d++) {
if (test_define_ispermutation(d)) {
@@ -1327,7 +1322,7 @@ static void list_geometries(void) {
// scenarios to run tests under power-loss
static void run_powerloss_none(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_) {
@@ -1336,14 +1331,14 @@ static void run_powerloss_none(
(void)suite;
// create block device and configuration
lfs2_emubd_t bd;
lfs_emubd_t bd;
struct lfs2_config cfg = {
struct lfs_config cfg = {
.context = &bd,
.read = lfs2_emubd_read,
.prog = lfs2_emubd_prog,
.erase = lfs2_emubd_erase,
.sync = lfs2_emubd_sync,
.read = lfs_emubd_read,
.prog = lfs_emubd_prog,
.erase = lfs_emubd_erase,
.sync = lfs_emubd_sync,
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.block_size = BLOCK_SIZE,
@@ -1351,15 +1346,12 @@ static void run_powerloss_none(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.metadata_max = METADATA_MAX,
.inline_max = INLINE_MAX,
#ifdef LFS2_MULTIVERSION
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
};
struct lfs2_emubd_config bdcfg = {
struct lfs_emubd_config bdcfg = {
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.erase_size = ERASE_SIZE,
@@ -1373,7 +1365,7 @@ static void run_powerloss_none(
.erase_sleep = test_erase_sleep,
};
int err = lfs2_emubd_create(&cfg, &bdcfg);
int err = lfs_emubd_create(&cfg, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1391,7 +1383,7 @@ static void run_powerloss_none(
printf("\n");
// cleanup
err = lfs2_emubd_destroy(&cfg);
err = lfs_emubd_destroy(&cfg);
if (err) {
fprintf(stderr, "error: could not destroy block device: %d\n", err);
exit(-1);
@@ -1404,7 +1396,7 @@ static void powerloss_longjmp(void *c) {
}
static void run_powerloss_linear(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_) {
@@ -1413,16 +1405,16 @@ static void run_powerloss_linear(
(void)suite;
// create block device and configuration
lfs2_emubd_t bd;
lfs_emubd_t bd;
jmp_buf powerloss_jmp;
volatile lfs2_emubd_powercycles_t i = 1;
volatile lfs_emubd_powercycles_t i = 1;
struct lfs2_config cfg = {
struct lfs_config cfg = {
.context = &bd,
.read = lfs2_emubd_read,
.prog = lfs2_emubd_prog,
.erase = lfs2_emubd_erase,
.sync = lfs2_emubd_sync,
.read = lfs_emubd_read,
.prog = lfs_emubd_prog,
.erase = lfs_emubd_erase,
.sync = lfs_emubd_sync,
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.block_size = BLOCK_SIZE,
@@ -1430,15 +1422,12 @@ static void run_powerloss_linear(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.metadata_max = METADATA_MAX,
.inline_max = INLINE_MAX,
#ifdef LFS2_MULTIVERSION
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
};
struct lfs2_emubd_config bdcfg = {
struct lfs_emubd_config bdcfg = {
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.erase_size = ERASE_SIZE,
@@ -1456,7 +1445,7 @@ static void run_powerloss_linear(
.powerloss_data = &powerloss_jmp,
};
int err = lfs2_emubd_create(&cfg, &bdcfg);
int err = lfs_emubd_create(&cfg, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1478,13 +1467,13 @@ static void run_powerloss_linear(
printf("powerloss ");
perm_printid(suite, case_, NULL, 0);
printf(":");
for (lfs2_emubd_powercycles_t j = 1; j <= i; j++) {
for (lfs_emubd_powercycles_t j = 1; j <= i; j++) {
leb16_print(j);
}
printf("\n");
i += 1;
lfs2_emubd_setpowercycles(&cfg, i);
lfs_emubd_setpowercycles(&cfg, i);
}
printf("finished ");
@@ -1492,7 +1481,7 @@ static void run_powerloss_linear(
printf("\n");
// cleanup
err = lfs2_emubd_destroy(&cfg);
err = lfs_emubd_destroy(&cfg);
if (err) {
fprintf(stderr, "error: could not destroy block device: %d\n", err);
exit(-1);
@@ -1500,7 +1489,7 @@ static void run_powerloss_linear(
}
static void run_powerloss_log(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_) {
@@ -1509,16 +1498,16 @@ static void run_powerloss_log(
(void)suite;
// create block device and configuration
lfs2_emubd_t bd;
lfs_emubd_t bd;
jmp_buf powerloss_jmp;
volatile lfs2_emubd_powercycles_t i = 1;
volatile lfs_emubd_powercycles_t i = 1;
struct lfs2_config cfg = {
struct lfs_config cfg = {
.context = &bd,
.read = lfs2_emubd_read,
.prog = lfs2_emubd_prog,
.erase = lfs2_emubd_erase,
.sync = lfs2_emubd_sync,
.read = lfs_emubd_read,
.prog = lfs_emubd_prog,
.erase = lfs_emubd_erase,
.sync = lfs_emubd_sync,
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.block_size = BLOCK_SIZE,
@@ -1526,15 +1515,12 @@ static void run_powerloss_log(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.metadata_max = METADATA_MAX,
.inline_max = INLINE_MAX,
#ifdef LFS2_MULTIVERSION
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
};
struct lfs2_emubd_config bdcfg = {
struct lfs_emubd_config bdcfg = {
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.erase_size = ERASE_SIZE,
@@ -1552,7 +1538,7 @@ static void run_powerloss_log(
.powerloss_data = &powerloss_jmp,
};
int err = lfs2_emubd_create(&cfg, &bdcfg);
int err = lfs_emubd_create(&cfg, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1574,13 +1560,13 @@ static void run_powerloss_log(
printf("powerloss ");
perm_printid(suite, case_, NULL, 0);
printf(":");
for (lfs2_emubd_powercycles_t j = 1; j <= i; j *= 2) {
for (lfs_emubd_powercycles_t j = 1; j <= i; j *= 2) {
leb16_print(j);
}
printf("\n");
i *= 2;
lfs2_emubd_setpowercycles(&cfg, i);
lfs_emubd_setpowercycles(&cfg, i);
}
printf("finished ");
@@ -1588,7 +1574,7 @@ static void run_powerloss_log(
printf("\n");
// cleanup
err = lfs2_emubd_destroy(&cfg);
err = lfs_emubd_destroy(&cfg);
if (err) {
fprintf(stderr, "error: could not destroy block device: %d\n", err);
exit(-1);
@@ -1596,23 +1582,23 @@ static void run_powerloss_log(
}
static void run_powerloss_cycles(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_) {
(void)suite;
// create block device and configuration
lfs2_emubd_t bd;
lfs_emubd_t bd;
jmp_buf powerloss_jmp;
volatile size_t i = 0;
struct lfs2_config cfg = {
struct lfs_config cfg = {
.context = &bd,
.read = lfs2_emubd_read,
.prog = lfs2_emubd_prog,
.erase = lfs2_emubd_erase,
.sync = lfs2_emubd_sync,
.read = lfs_emubd_read,
.prog = lfs_emubd_prog,
.erase = lfs_emubd_erase,
.sync = lfs_emubd_sync,
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.block_size = BLOCK_SIZE,
@@ -1620,15 +1606,12 @@ static void run_powerloss_cycles(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.metadata_max = METADATA_MAX,
.inline_max = INLINE_MAX,
#ifdef LFS2_MULTIVERSION
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
};
struct lfs2_emubd_config bdcfg = {
struct lfs_emubd_config bdcfg = {
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.erase_size = ERASE_SIZE,
@@ -1646,7 +1629,7 @@ static void run_powerloss_cycles(
.powerloss_data = &powerloss_jmp,
};
int err = lfs2_emubd_create(&cfg, &bdcfg);
int err = lfs_emubd_create(&cfg, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1671,7 +1654,7 @@ static void run_powerloss_cycles(
printf("\n");
i += 1;
lfs2_emubd_setpowercycles(&cfg,
lfs_emubd_setpowercycles(&cfg,
(i < cycle_count) ? cycles[i] : 0);
}
@@ -1680,7 +1663,7 @@ static void run_powerloss_cycles(
printf("\n");
// cleanup
err = lfs2_emubd_destroy(&cfg);
err = lfs_emubd_destroy(&cfg);
if (err) {
fprintf(stderr, "error: could not destroy block device: %d\n", err);
exit(-1);
@@ -1688,15 +1671,15 @@ static void run_powerloss_cycles(
}
struct powerloss_exhaustive_state {
struct lfs2_config *cfg;
struct lfs_config *cfg;
lfs2_emubd_t *branches;
lfs_emubd_t *branches;
size_t branch_count;
size_t branch_capacity;
};
struct powerloss_exhaustive_cycles {
lfs2_emubd_powercycles_t *cycles;
lfs_emubd_powercycles_t *cycles;
size_t cycle_count;
size_t cycle_capacity;
};
@@ -1704,9 +1687,9 @@ struct powerloss_exhaustive_cycles {
static void powerloss_exhaustive_branch(void *c) {
struct powerloss_exhaustive_state *state = c;
// append to branches
lfs2_emubd_t *branch = mappend(
lfs_emubd_t *branch = mappend(
(void**)&state->branches,
sizeof(lfs2_emubd_t),
sizeof(lfs_emubd_t),
&state->branch_count,
&state->branch_capacity);
if (!branch) {
@@ -1715,22 +1698,22 @@ static void powerloss_exhaustive_branch(void *c) {
}
// create copy-on-write copy
int err = lfs2_emubd_copy(state->cfg, branch);
int err = lfs_emubd_copy(state->cfg, branch);
if (err) {
fprintf(stderr, "error: exhaustive: could not create bd copy\n");
exit(-1);
}
// also trigger on next power cycle
lfs2_emubd_setpowercycles(state->cfg, 1);
lfs_emubd_setpowercycles(state->cfg, 1);
}
static void run_powerloss_exhaustive_layer(
struct powerloss_exhaustive_cycles *cycles,
const struct test_suite *suite,
const struct test_case *case_,
struct lfs2_config *cfg,
struct lfs2_emubd_config *bdcfg,
struct lfs_config *cfg,
struct lfs_emubd_config *bdcfg,
size_t depth) {
(void)suite;
@@ -1743,14 +1726,14 @@ static void run_powerloss_exhaustive_layer(
// run through the test without additional powerlosses, collecting possible
// branches as we do so
lfs2_emubd_setpowercycles(state.cfg, depth > 0 ? 1 : 0);
lfs_emubd_setpowercycles(state.cfg, depth > 0 ? 1 : 0);
bdcfg->powerloss_data = &state;
// run the tests
case_->run(cfg);
// aggressively clean up memory here to try to keep our memory usage low
int err = lfs2_emubd_destroy(cfg);
int err = lfs_emubd_destroy(cfg);
if (err) {
fprintf(stderr, "error: could not destroy block device: %d\n", err);
exit(-1);
@@ -1759,9 +1742,9 @@ static void run_powerloss_exhaustive_layer(
// recurse into each branch
for (size_t i = 0; i < state.branch_count; i++) {
// first push and print the branch
lfs2_emubd_powercycles_t *cycle = mappend(
lfs_emubd_powercycles_t *cycle = mappend(
(void**)&cycles->cycles,
sizeof(lfs2_emubd_powercycles_t),
sizeof(lfs_emubd_powercycles_t),
&cycles->cycle_count,
&cycles->cycle_capacity);
if (!cycle) {
@@ -1789,7 +1772,7 @@ static void run_powerloss_exhaustive_layer(
}
static void run_powerloss_exhaustive(
const lfs2_emubd_powercycles_t *cycles,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
const struct test_suite *suite,
const struct test_case *case_) {
@@ -1797,14 +1780,14 @@ static void run_powerloss_exhaustive(
(void)suite;
// create block device and configuration
lfs2_emubd_t bd;
lfs_emubd_t bd;
struct lfs2_config cfg = {
struct lfs_config cfg = {
.context = &bd,
.read = lfs2_emubd_read,
.prog = lfs2_emubd_prog,
.erase = lfs2_emubd_erase,
.sync = lfs2_emubd_sync,
.read = lfs_emubd_read,
.prog = lfs_emubd_prog,
.erase = lfs_emubd_erase,
.sync = lfs_emubd_sync,
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.block_size = BLOCK_SIZE,
@@ -1812,15 +1795,12 @@ static void run_powerloss_exhaustive(
.block_cycles = BLOCK_CYCLES,
.cache_size = CACHE_SIZE,
.lookahead_size = LOOKAHEAD_SIZE,
.compact_thresh = COMPACT_THRESH,
.metadata_max = METADATA_MAX,
.inline_max = INLINE_MAX,
#ifdef LFS2_MULTIVERSION
#ifdef LFS_MULTIVERSION
.disk_version = DISK_VERSION,
#endif
};
struct lfs2_emubd_config bdcfg = {
struct lfs_emubd_config bdcfg = {
.read_size = READ_SIZE,
.prog_size = PROG_SIZE,
.erase_size = ERASE_SIZE,
@@ -1837,7 +1817,7 @@ static void run_powerloss_exhaustive(
.powerloss_data = NULL,
};
int err = lfs2_emubd_create(&cfg, &bdcfg);
int err = lfs_emubd_create(&cfg, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -2326,7 +2306,7 @@ invalid_define:
// comma-separated read/prog/erase/count
if (*optarg == '{') {
lfs2_size_t sizes[4];
lfs_size_t sizes[4];
size_t count = 0;
char *s = optarg + 1;
@@ -2375,7 +2355,7 @@ invalid_define:
// leb16-encoded read/prog/erase/count
if (*optarg == ':') {
lfs2_size_t sizes[4];
lfs_size_t sizes[4];
size_t count = 0;
char *s = optarg + 1;
@@ -2471,16 +2451,16 @@ geometry_next:
// comma-separated permutation
if (*optarg == '{') {
lfs2_emubd_powercycles_t *cycles = NULL;
lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0;
size_t cycle_capacity = 0;
char *s = optarg + 1;
while (true) {
char *parsed = NULL;
*(lfs2_emubd_powercycles_t*)mappend(
*(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles,
sizeof(lfs2_emubd_powercycles_t),
sizeof(lfs_emubd_powercycles_t),
&cycle_count,
&cycle_capacity)
= strtoumax(s, &parsed, 0);
@@ -2508,7 +2488,7 @@ geometry_next:
// leb16-encoded permutation
if (*optarg == ':') {
lfs2_emubd_powercycles_t *cycles = NULL;
lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0;
size_t cycle_capacity = 0;
@@ -2520,9 +2500,9 @@ geometry_next:
break;
}
*(lfs2_emubd_powercycles_t*)mappend(
*(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles,
sizeof(lfs2_emubd_powercycles_t),
sizeof(lfs_emubd_powercycles_t),
&cycle_count,
&cycle_capacity) = x;
s = parsed;
@@ -2701,7 +2681,7 @@ getopt_done: ;
for (; argc > optind; optind++) {
test_define_t *defines = NULL;
size_t define_count = 0;
lfs2_emubd_powercycles_t *cycles = NULL;
lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0;
// parse name, can be suite or case
@@ -2742,7 +2722,7 @@ getopt_done: ;
if (d >= define_count) {
// align to power of two to avoid any superlinear growth
size_t ncount = 1 << lfs2_npw2(d+1);
size_t ncount = 1 << lfs_npw2(d+1);
defines = realloc(defines,
ncount*sizeof(test_define_t));
memset(defines+define_count, 0,
@@ -2757,9 +2737,9 @@ getopt_done: ;
size_t cycle_capacity = 0;
while (*cycles_ != '\0') {
char *parsed = NULL;
*(lfs2_emubd_powercycles_t*)mappend(
*(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles,
sizeof(lfs2_emubd_powercycles_t),
sizeof(lfs_emubd_powercycles_t),
&cycle_count,
&cycle_capacity)
= leb16_parse(cycles_, &parsed);

View File

@@ -8,20 +8,20 @@
#define TEST_RUNNER_H
// override LFS2_TRACE
// override LFS_TRACE
void test_trace(const char *fmt, ...);
#define LFS2_TRACE_(fmt, ...) \
#define LFS_TRACE_(fmt, ...) \
test_trace("%s:%d:trace: " fmt "%s\n", \
__FILE__, \
__LINE__, \
__VA_ARGS__)
#define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#define LFS2_EMUBD_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
#define LFS_EMUBD_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
// note these are indirectly included in any generated files
#include "bd/lfs2_emubd.h"
#include "bd/lfs_emubd.h"
#include <stdio.h>
// give source a chance to define feature macros
@@ -30,7 +30,7 @@ void test_trace(const char *fmt, ...);
// generated test configurations
struct lfs2_config;
struct lfs_config;
enum test_flags {
TEST_REENTRANT = 0x1,
@@ -51,7 +51,7 @@ struct test_case {
const test_define_t *defines;
bool (*filter)(void);
void (*run)(struct lfs2_config *cfg);
void (*run)(struct lfs_config *cfg);
};
struct test_suite {
@@ -88,15 +88,12 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT_i 5
#define CACHE_SIZE_i 6
#define LOOKAHEAD_SIZE_i 7
#define COMPACT_THRESH_i 8
#define METADATA_MAX_i 9
#define INLINE_MAX_i 10
#define BLOCK_CYCLES_i 11
#define ERASE_VALUE_i 12
#define ERASE_CYCLES_i 13
#define BADBLOCK_BEHAVIOR_i 14
#define POWERLOSS_BEHAVIOR_i 15
#define DISK_VERSION_i 16
#define BLOCK_CYCLES_i 8
#define ERASE_VALUE_i 9
#define ERASE_CYCLES_i 10
#define BADBLOCK_BEHAVIOR_i 11
#define POWERLOSS_BEHAVIOR_i 12
#define DISK_VERSION_i 13
#define READ_SIZE TEST_DEFINE(READ_SIZE_i)
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i)
@@ -106,9 +103,6 @@ intmax_t test_define(size_t define);
#define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i)
#define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i)
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
#define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i)
#define METADATA_MAX TEST_DEFINE(METADATA_MAX_i)
#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i)
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i)
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i)
@@ -122,21 +116,18 @@ intmax_t test_define(size_t define);
TEST_DEF(ERASE_SIZE, 0) \
TEST_DEF(ERASE_COUNT, (1024*1024)/ERASE_SIZE) \
TEST_DEF(BLOCK_SIZE, ERASE_SIZE) \
TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs2_max(BLOCK_SIZE/ERASE_SIZE,1)) \
TEST_DEF(CACHE_SIZE, lfs2_max(64,lfs2_max(READ_SIZE,PROG_SIZE))) \
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(LOOKAHEAD_SIZE, 16) \
TEST_DEF(COMPACT_THRESH, 0) \
TEST_DEF(METADATA_MAX, 0) \
TEST_DEF(INLINE_MAX, 0) \
TEST_DEF(BLOCK_CYCLES, -1) \
TEST_DEF(ERASE_VALUE, 0xff) \
TEST_DEF(ERASE_CYCLES, 0) \
TEST_DEF(BADBLOCK_BEHAVIOR, LFS2_EMUBD_BADBLOCK_PROGERROR) \
TEST_DEF(POWERLOSS_BEHAVIOR, LFS2_EMUBD_POWERLOSS_NOOP) \
TEST_DEF(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR) \
TEST_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) \
TEST_DEF(DISK_VERSION, 0)
#define TEST_GEOMETRY_DEFINE_COUNT 4
#define TEST_IMPLICIT_DEFINE_COUNT 17
#define TEST_IMPLICIT_DEFINE_COUNT 14
#endif

View File

@@ -350,7 +350,7 @@ def compile(bench_paths, **args):
# create case run function
f.writeln('void __bench__%s__run('
'__attribute__((unused)) struct lfs2_config *cfg) {'
'__attribute__((unused)) struct lfs_config *cfg) {'
% (case.name))
f.writeln(4*' '+'// bench case %s' % case.name)
if case.code_lineno is not None:
@@ -399,20 +399,17 @@ def compile(bench_paths, **args):
'void);'
% (case.name))
f.writeln('extern void __bench__%s__run('
'struct lfs2_config *cfg);'
'struct lfs_config *cfg);'
% (case.name))
f.writeln()
# create suite struct
f.writeln('#if defined(__APPLE__)')
f.writeln('__attribute__((section("__DATA,_bench_suites")))')
f.writeln('#else')
#
# note we place this in the custom bench_suites section with
# minimum alignment, otherwise GCC ups the alignment to
# 32-bytes for some reason
f.writeln('__attribute__((section("_bench_suites"), '
'aligned(1)))')
f.writeln('#endif')
f.writeln('const struct bench_suite __bench__%s__suite = {'
% suite.name)
f.writeln(4*' '+'.name = "%s",' % suite.name)

View File

@@ -4,7 +4,7 @@
# of a codebase that don't conflict at compile time.
#
# Example:
# $ ./scripts/changeprefix.py lfs2 lfs23
# $ ./scripts/changeprefix.py lfs lfs3
#
# Copyright (c) 2022, The littlefs authors.
# Copyright (c) 2019, Arm Limited. All rights reserved.
@@ -73,7 +73,7 @@ def changefile(from_prefix, to_prefix, from_path, to_path, *,
shutil.copystat(from_path, to_path)
if to_path_temp:
shutil.move(to_path, from_path)
os.rename(to_path, from_path)
elif from_path != '-':
os.remove(from_path)

View File

@@ -5,7 +5,7 @@
# by Linux's Bloat-O-Meter.
#
# Example:
# ./scripts/code.py lfs2.o lfs2_util.o -Ssize
# ./scripts/code.py lfs.o lfs_util.o -Ssize
#
# Copyright (c) 2022, The littlefs authors.
# Copyright (c) 2020, Arm Limited. All rights reserved.

View File

@@ -4,7 +4,7 @@
#
# Example:
# ./scripts/cov.py \
# lfs2.t.a.gcda lfs2_util.t.a.gcda \
# lfs.t.a.gcda lfs_util.t.a.gcda \
# -Flfs.c -Flfs_util.c -slines
#
# Copyright (c) 2022, The littlefs authors.

View File

@@ -5,7 +5,7 @@
# by Linux's Bloat-O-Meter.
#
# Example:
# ./scripts/data.py lfs2.o lfs2_util.o -Ssize
# ./scripts/data.py lfs.o lfs_util.o -Ssize
#
# Copyright (c) 2022, The littlefs authors.
# Copyright (c) 2020, Arm Limited. All rights reserved.

View File

@@ -3,7 +3,7 @@
# Preprocessor that makes asserts easier to debug.
#
# Example:
# ./scripts/prettyasserts.py -p LFS2_ASSERT lfs2.c -o lfs2.a.c
# ./scripts/prettyasserts.py -p LFS_ASSERT lfs.c -o lfs.a.c
#
# Copyright (c) 2022, The littlefs authors.
# Copyright (c) 2020, Arm Limited. All rights reserved.
@@ -35,10 +35,10 @@ LEXEMES = {
'assert': ['assert'],
'arrow': ['=>'],
'string': [r'"(?:\\.|[^"])*"', r"'(?:\\.|[^'])\'"],
'paren': [r'\(', r'\)'],
'paren': ['\(', '\)'],
'cmp': CMP.keys(),
'logic': [r'\&\&', r'\|\|'],
'sep': [':', ';', r'\{', r'\}', ','],
'logic': ['\&\&', '\|\|'],
'sep': [':', ';', '\{', '\}', ','],
'op': ['->'], # specifically ops that conflict with cmp
}
@@ -86,13 +86,6 @@ def write_header(f, limit=LIMIT):
f.writeln("}")
f.writeln()
f.writeln("__attribute__((unused))")
f.writeln("static void __pretty_assert_print_ptr(")
f.writeln(" const void *v, size_t size) {")
f.writeln(" (void)size;")
f.writeln(" printf(\"%p\", v);")
f.writeln("}")
f.writeln()
f.writeln("__attribute__((unused))")
f.writeln("static void __pretty_assert_print_mem(")
f.writeln(" const void *v, size_t size) {")
f.writeln(" const uint8_t *v_ = v;")
@@ -190,23 +183,6 @@ def write_header(f, limit=LIMIT):
f.writeln(" _rh, strlen(_rh)); \\")
f.writeln(" } \\")
f.writeln("} while (0)")
for op, cmp in sorted(CMP.items()):
# Only EQ and NE are supported when compared to NULL.
if cmp not in ['eq', 'ne']:
continue
f.writeln("#define __PRETTY_ASSERT_PTR_%s(lh, rh) do { \\"
% cmp.upper())
f.writeln(" const void *_lh = (const void*)(uintptr_t)lh; \\")
f.writeln(" const void *_rh = (const void*)(uintptr_t)rh; \\")
f.writeln(" if (!(_lh %s _rh)) { \\" % op)
f.writeln(" __pretty_assert_fail( \\")
f.writeln(" __FILE__, __LINE__, \\")
f.writeln(" __pretty_assert_print_ptr, \"%s\", \\"
% cmp)
f.writeln(" (const void*){_lh}, 0, \\")
f.writeln(" (const void*){_rh}, 0); \\")
f.writeln(" } \\")
f.writeln("} while (0)")
f.writeln()
f.writeln()
@@ -325,8 +301,6 @@ def p_assert(p):
cmp = p.expect('cmp') ; p.accept('ws')
rh = p_expr(p) ; p.accept('ws')
p.expect(')')
if rh == 'NULL' or lh == 'NULL':
return mkassert('ptr', CMP[cmp], lh, rh)
return mkassert('int', CMP[cmp], lh, rh)
except ParseFailure:
p.pop(state)

View File

@@ -4,7 +4,7 @@
# report as infinite stack usage.
#
# Example:
# ./scripts/stack.py lfs2.ci lfs2_util.ci -Slimit
# ./scripts/stack.py lfs.ci lfs_util.ci -Slimit
#
# Copyright (c) 2022, The littlefs authors.
# SPDX-License-Identifier: BSD-3-Clause

View File

@@ -3,7 +3,7 @@
# Script to find struct sizes.
#
# Example:
# ./scripts/structs.py lfs2.o lfs2_util.o -Ssize
# ./scripts/structs.py lfs.o lfs_util.o -Ssize
#
# Copyright (c) 2022, The littlefs authors.
# SPDX-License-Identifier: BSD-3-Clause

View File

@@ -3,10 +3,10 @@
# Script to summarize the outputs of other scripts. Operates on CSV files.
#
# Example:
# ./scripts/code.py lfs2.o lfs2_util.o -q -o lfs2.code.csv
# ./scripts/data.py lfs2.o lfs2_util.o -q -o lfs2.data.csv
# ./scripts/summary.py lfs2.code.csv lfs2.data.csv -q -o lfs2.csv
# ./scripts/summary.py -Y lfs2.csv -f code=code_size,data=data_size
# ./scripts/code.py lfs.o lfs_util.o -q -o lfs.code.csv
# ./scripts/data.py lfs.o lfs_util.o -q -o lfs.data.csv
# ./scripts/summary.py lfs.code.csv lfs.data.csv -q -o lfs.csv
# ./scripts/summary.py -Y lfs.csv -f code=code_size,data=data_size
#
# Copyright (c) 2022, The littlefs authors.
# SPDX-License-Identifier: BSD-3-Clause

View File

@@ -102,9 +102,9 @@ class TestCase:
# the runner itself.
for v_ in csplit(v):
m = re.search(r'\brange\b\s*\('
r'(?P<start>[^,\s]*)'
r'\s*(?:,\s*(?P<stop>[^,\s]*)'
r'\s*(?:,\s*(?P<step>[^,\s]*)\s*)?)?\)',
'(?P<start>[^,\s]*)'
'\s*(?:,\s*(?P<stop>[^,\s]*)'
'\s*(?:,\s*(?P<step>[^,\s]*)\s*)?)?\)',
v_)
if m:
start = (int(m.group('start'), 0)
@@ -163,8 +163,8 @@ class TestSuite:
code_linenos = []
for i, line in enumerate(f):
match = re.match(
r'(?P<case>\[\s*cases\s*\.\s*(?P<name>\w+)\s*\])'
r'|' r'(?P<code>code\s*=)',
'(?P<case>\[\s*cases\s*\.\s*(?P<name>\w+)\s*\])'
'|' '(?P<code>code\s*=)',
line)
if match and match.group('case'):
case_linenos.append((i+1, match.group('name')))
@@ -358,7 +358,7 @@ def compile(test_paths, **args):
# create case run function
f.writeln('void __test__%s__run('
'__attribute__((unused)) struct lfs2_config *cfg) {'
'__attribute__((unused)) struct lfs_config *cfg) {'
% (case.name))
f.writeln(4*' '+'// test case %s' % case.name)
if case.code_lineno is not None:
@@ -407,20 +407,17 @@ def compile(test_paths, **args):
'void);'
% (case.name))
f.writeln('extern void __test__%s__run('
'struct lfs2_config *cfg);'
'struct lfs_config *cfg);'
% (case.name))
f.writeln()
# create suite struct
f.writeln('#if defined(__APPLE__)')
f.writeln('__attribute__((section("__DATA,_test_suites")))')
f.writeln('#else')
#
# note we place this in the custom test_suites section with
# minimum alignment, otherwise GCC ups the alignment to
# 32-bytes for some reason
f.writeln('__attribute__((section("_test_suites"), '
'aligned(1)))')
f.writeln('#endif')
f.writeln('const struct test_suite __test__%s__suite = {'
% suite.name)
f.writeln(4*' '+'.name = "%s",' % suite.name)
@@ -605,9 +602,9 @@ def find_perms(runner_, ids=[], **args):
errors='replace',
close_fds=False)
pattern = re.compile(
r'^(?P<case>[^\s]+)'
r'\s+(?P<flags>[^\s]+)'
r'\s+(?P<filtered>\d+)/(?P<perms>\d+)')
'^(?P<case>[^\s]+)'
'\s+(?P<flags>[^\s]+)'
'\s+(?P<filtered>\d+)/(?P<perms>\d+)')
# skip the first line
for line in it.islice(proc.stdout, 1, None):
m = pattern.match(line)
@@ -635,8 +632,8 @@ def find_perms(runner_, ids=[], **args):
errors='replace',
close_fds=False)
pattern = re.compile(
r'^(?P<case>[^\s]+)'
r'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
'^(?P<case>[^\s]+)'
'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
# skip the first line
for line in it.islice(proc.stdout, 1, None):
m = pattern.match(line)
@@ -679,8 +676,8 @@ def find_path(runner_, id, **args):
errors='replace',
close_fds=False)
pattern = re.compile(
r'^(?P<case>[^\s]+)'
r'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
'^(?P<case>[^\s]+)'
'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
# skip the first line
for line in it.islice(proc.stdout, 1, None):
m = pattern.match(line)
@@ -709,7 +706,7 @@ def find_defines(runner_, id, **args):
errors='replace',
close_fds=False)
defines = co.OrderedDict()
pattern = re.compile(r'^(?P<define>\w+)=(?P<value>.+)')
pattern = re.compile('^(?P<define>\w+)=(?P<value>.+)')
for line in proc.stdout:
m = pattern.match(line)
if m:
@@ -784,12 +781,12 @@ def run_stage(name, runner_, ids, stdout_, trace_, output_, **args):
failures = []
killed = False
pattern = re.compile(r'^(?:'
r'(?P<op>running|finished|skipped|powerloss) '
r'(?P<id>(?P<case>[^:]+)[^\s]*)'
r'|' r'(?P<path>[^:]+):(?P<lineno>\d+):(?P<op_>assert):'
r' *(?P<message>.*)'
r')$')
pattern = re.compile('^(?:'
'(?P<op>running|finished|skipped|powerloss) '
'(?P<id>(?P<case>[^:]+)[^\s]*)'
'|' '(?P<path>[^:]+):(?P<lineno>\d+):(?P<op_>assert):'
' *(?P<message>.*)'
')$')
locals = th.local()
children = set()

File diff suppressed because it is too large Load Diff

View File

@@ -1,316 +1,316 @@
[cases.test_attrs_get_set]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "hello") => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
lfs2_setattr(&lfs2, "hello", 'A', "aaaa", 4) => 0;
lfs2_setattr(&lfs2, "hello", 'B', "bbbbbb", 6) => 0;
lfs2_setattr(&lfs2, "hello", 'C', "ccccc", 5) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "hello", 'B', "", 0) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 0;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "hello", 'B', "", 0) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_removeattr(&lfs2, "hello", 'B') => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => LFS2_ERR_NOATTR;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_removeattr(&lfs, "hello", 'B') => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "hello", 'B', "dddddd", 6) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "hello", 'B', "eee", 3) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 3;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "hello", 'A', buffer, LFS2_ATTR_MAX+1) => LFS2_ERR_NOSPC;
lfs2_setattr(&lfs2, "hello", 'B', "fffffffff", 9) => 0;
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 6) => 9;
lfs2_getattr(&lfs2, "hello", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer));
lfs2_getattr(&lfs2, "hello", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "hello", 'B', buffer+4, 9) => 9;
lfs2_getattr(&lfs2, "hello", 'C', buffer+13, 5) => 5;
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello");
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0;
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
'''
[cases.test_attrs_get_set_root]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "hello") => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
lfs2_setattr(&lfs2, "/", 'A', "aaaa", 4) => 0;
lfs2_setattr(&lfs2, "/", 'B', "bbbbbb", 6) => 0;
lfs2_setattr(&lfs2, "/", 'C', "ccccc", 5) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0;
lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "/", 'B', "", 0) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 0;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "/", 'B', "", 0) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_removeattr(&lfs2, "/", 'B') => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => LFS2_ERR_NOATTR;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_removeattr(&lfs, "/", 'B') => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "/", 'B', "dddddd", 6) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 6;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "/", 'B', "eee", 3) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 3;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
lfs2_setattr(&lfs2, "/", 'A', buffer, LFS2_ATTR_MAX+1) => LFS2_ERR_NOSPC;
lfs2_setattr(&lfs2, "/", 'B', "fffffffff", 9) => 0;
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 6) => 9;
lfs2_getattr(&lfs2, "/", 'C', buffer+10, 5) => 5;
lfs2_unmount(&lfs2) => 0;
lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer));
lfs2_getattr(&lfs2, "/", 'A', buffer, 4) => 4;
lfs2_getattr(&lfs2, "/", 'B', buffer+4, 9) => 9;
lfs2_getattr(&lfs2, "/", 'C', buffer+13, 5) => 5;
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello");
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0;
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
'''
[cases.test_attrs_get_set_file]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "hello") => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
struct lfs2_attr attrs1[] = {
struct lfs_attr attrs1[] = {
{'A', buffer, 4},
{'B', buffer+4, 6},
{'C', buffer+10, 5},
};
struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer, "aaaa", 4);
memcpy(buffer+4, "bbbbbb", 6);
memcpy(buffer+10, "ccccc", 5);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
memset(buffer, 0, 15);
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "bbbbbb", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[1].size = 0;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0;
memset(buffer, 0, 15);
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "dddddd", 6);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
memset(buffer, 0, 15);
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "dddddd", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[1].size = 3;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
memcpy(buffer+4, "eee", 3);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
memset(buffer, 0, 15);
attrs1[1].size = 6;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
memcmp(buffer+10, "ccccc", 5) => 0;
attrs1[0].size = LFS2_ATTR_MAX+1;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1)
=> LFS2_ERR_NOSPC;
attrs1[0].size = LFS_ATTR_MAX+1;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1)
=> LFS_ERR_NOSPC;
struct lfs2_attr attrs2[] = {
struct lfs_attr attrs2[] = {
{'A', buffer, 4},
{'B', buffer+4, 9},
{'C', buffer+13, 5},
};
struct lfs2_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDWR, &cfg2) => 0;
struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0;
memcpy(buffer+4, "fffffffff", 9);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
attrs1[0].size = 4;
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg1) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer));
struct lfs2_attr attrs3[] = {
struct lfs_attr attrs3[] = {
{'A', buffer, 4},
{'B', buffer+4, 9},
{'C', buffer+13, 5},
};
struct lfs2_file_config cfg3 = {.attrs=attrs3, .attr_count=3};
struct lfs_file_config cfg3 = {.attrs=attrs3, .attr_count=3};
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_RDONLY, &cfg3) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0;
lfs_file_close(&lfs, &file) => 0;
memcmp(buffer, "aaaa", 4) => 0;
memcmp(buffer+4, "fffffffff", 9) => 0;
memcmp(buffer+13, "ccccc", 5) => 0;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => strlen("hello");
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
memcmp(buffer, "hello", strlen("hello")) => 0;
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
'''
[cases.test_attrs_deferred_file]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "hello") => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "hello/hello", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_write(&lfs2, &file, "hello", strlen("hello")) => strlen("hello");
lfs2_file_close(&lfs2, &file);
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_setattr(&lfs2, "hello/hello", 'B', "fffffffff", 9) => 0;
lfs2_setattr(&lfs2, "hello/hello", 'C', "ccccc", 5) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0;
lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
struct lfs2_attr attrs1[] = {
struct lfs_attr attrs1[] = {
{'B', "gggg", 4},
{'C', "", 0},
{'D', "hhhh", 4},
};
struct lfs2_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3};
lfs2_file_opencfg(&lfs2, &file, "hello/hello", LFS2_O_WRONLY, &cfg1) => 0;
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
lfs2_getattr(&lfs2, "hello/hello", 'B', buffer, 9) => 9;
lfs2_getattr(&lfs2, "hello/hello", 'C', buffer+9, 9) => 5;
lfs2_getattr(&lfs2, "hello/hello", 'D', buffer+18, 9) => LFS2_ERR_NOATTR;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR;
memcmp(buffer, "fffffffff", 9) => 0;
memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0;
memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0;
lfs2_file_sync(&lfs2, &file) => 0;
lfs2_getattr(&lfs2, "hello/hello", 'B', buffer, 9) => 4;
lfs2_getattr(&lfs2, "hello/hello", 'C', buffer+9, 9) => 0;
lfs2_getattr(&lfs2, "hello/hello", 'D', buffer+18, 9) => 4;
lfs_file_sync(&lfs, &file) => 0;
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4;
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0;
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4;
memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0;
memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0;
memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -6,78 +6,78 @@ defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
'LFS2_EMUBD_BADBLOCK_PROGERROR',
'LFS2_EMUBD_BADBLOCK_ERASEERROR',
'LFS2_EMUBD_BADBLOCK_READERROR',
'LFS2_EMUBD_BADBLOCK_PROGNOOP',
'LFS2_EMUBD_BADBLOCK_ERASENOOP',
'LFS_EMUBD_BADBLOCK_PROGERROR',
'LFS_EMUBD_BADBLOCK_ERASEERROR',
'LFS_EMUBD_BADBLOCK_READERROR',
'LFS_EMUBD_BADBLOCK_PROGNOOP',
'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.NAMEMULT = 64
defines.FILEMULT = 1
code = '''
for (lfs2_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) {
lfs2_emubd_setwear(cfg, badblock-1, 0) => 0;
lfs2_emubd_setwear(cfg, badblock, 0xffffffff) => 0;
for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) {
lfs_emubd_setwear(cfg, badblock-1, 0) => 0;
lfs_emubd_setwear(cfg, badblock, 0xffffffff) => 0;
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
lfs_mkdir(&lfs, (char*)buffer) => 0;
buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs2_size_t size = NAMEMULT;
lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
struct lfs2_info info;
lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS2_TYPE_DIR;
struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
int size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024];
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
}
'''
@@ -86,78 +86,78 @@ defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
'LFS2_EMUBD_BADBLOCK_PROGERROR',
'LFS2_EMUBD_BADBLOCK_ERASEERROR',
'LFS2_EMUBD_BADBLOCK_READERROR',
'LFS2_EMUBD_BADBLOCK_PROGNOOP',
'LFS2_EMUBD_BADBLOCK_ERASENOOP',
'LFS_EMUBD_BADBLOCK_PROGERROR',
'LFS_EMUBD_BADBLOCK_ERASEERROR',
'LFS_EMUBD_BADBLOCK_READERROR',
'LFS_EMUBD_BADBLOCK_PROGNOOP',
'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.NAMEMULT = 64
defines.FILEMULT = 1
code = '''
for (lfs2_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
lfs2_emubd_setwear(cfg, i+2, 0xffffffff) => 0;
for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
lfs_emubd_setwear(cfg, i+2, 0xffffffff) => 0;
}
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
lfs_mkdir(&lfs, (char*)buffer) => 0;
buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs2_size_t size = NAMEMULT;
lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
struct lfs2_info info;
lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS2_TYPE_DIR;
struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
lfs2_size_t size = NAMEMULT;
lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024];
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_badblocks_alternating_corruption] # (causes cascading failures)
@@ -165,78 +165,78 @@ defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
'LFS2_EMUBD_BADBLOCK_PROGERROR',
'LFS2_EMUBD_BADBLOCK_ERASEERROR',
'LFS2_EMUBD_BADBLOCK_READERROR',
'LFS2_EMUBD_BADBLOCK_PROGNOOP',
'LFS2_EMUBD_BADBLOCK_ERASENOOP',
'LFS_EMUBD_BADBLOCK_PROGERROR',
'LFS_EMUBD_BADBLOCK_ERASEERROR',
'LFS_EMUBD_BADBLOCK_READERROR',
'LFS_EMUBD_BADBLOCK_PROGNOOP',
'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.NAMEMULT = 64
defines.FILEMULT = 1
code = '''
for (lfs2_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
lfs2_emubd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0;
for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
lfs_emubd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0;
}
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
lfs2_mkdir(&lfs2, (char*)buffer) => 0;
lfs_mkdir(&lfs, (char*)buffer) => 0;
buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, (char*)buffer,
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs2_size_t size = NAMEMULT;
lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
struct lfs2_info info;
lfs2_stat(&lfs2, (char*)buffer, &info) => 0;
info.type => LFS2_TYPE_DIR;
struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
buffer[NAMEMULT] = '/';
for (int j = 0; j < NAMEMULT; j++) {
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, (char*)buffer, LFS2_O_RDONLY) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
lfs2_size_t size = NAMEMULT;
lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024];
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(buffer, rbuffer, size) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# other corner cases
@@ -244,17 +244,17 @@ code = '''
defines.ERASE_CYCLES = 0xffffffff
defines.ERASE_VALUE = [0x00, 0xff, -1]
defines.BADBLOCK_BEHAVIOR = [
'LFS2_EMUBD_BADBLOCK_PROGERROR',
'LFS2_EMUBD_BADBLOCK_ERASEERROR',
'LFS2_EMUBD_BADBLOCK_READERROR',
'LFS2_EMUBD_BADBLOCK_PROGNOOP',
'LFS2_EMUBD_BADBLOCK_ERASENOOP',
'LFS_EMUBD_BADBLOCK_PROGERROR',
'LFS_EMUBD_BADBLOCK_ERASEERROR',
'LFS_EMUBD_BADBLOCK_READERROR',
'LFS_EMUBD_BADBLOCK_PROGNOOP',
'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
code = '''
lfs2_emubd_setwear(cfg, 0, 0xffffffff) => 0;
lfs2_emubd_setwear(cfg, 1, 0xffffffff) => 0;
lfs_emubd_setwear(cfg, 0, 0xffffffff) => 0;
lfs_emubd_setwear(cfg, 1, 0xffffffff) => 0;
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => LFS2_ERR_NOSPC;
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
lfs_t lfs;
lfs_format(&lfs, cfg) => LFS_ERR_NOSPC;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''

View File

@@ -8,23 +8,23 @@
defines.READ = ['READ_SIZE', 'BLOCK_SIZE']
defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE']
code = '''
uint8_t buffer[lfs2_max(READ, PROG)];
uint8_t buffer[lfs_max(READ, PROG)];
// write data
cfg->erase(cfg, 0) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (i+j) % 251;
}
cfg->prog(cfg, 0, i, buffer, PROG) => 0;
}
// read data
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, 0, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (i+j) % 251);
}
}
'''
@@ -33,14 +33,14 @@ code = '''
defines.READ = ['READ_SIZE', 'BLOCK_SIZE']
defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE']
code = '''
uint8_t buffer[lfs2_max(READ, PROG)];
lfs2_block_t block;
uint8_t buffer[lfs_max(READ, PROG)];
lfs_block_t block;
// write block 0
block = 0;
cfg->erase(cfg, block) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (block+i+j) % 251;
}
cfg->prog(cfg, block, i, buffer, PROG) => 0;
@@ -48,19 +48,19 @@ code = '''
// read block 0
block = 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
// write block 1
block = 1;
cfg->erase(cfg, block) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (block+i+j) % 251;
}
cfg->prog(cfg, block, i, buffer, PROG) => 0;
@@ -68,21 +68,21 @@ code = '''
// read block 1
block = 1;
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
// read block 0 again
block = 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
'''
@@ -91,14 +91,14 @@ code = '''
defines.READ = ['READ_SIZE', 'BLOCK_SIZE']
defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE']
code = '''
uint8_t buffer[lfs2_max(READ, PROG)];
lfs2_block_t block;
uint8_t buffer[lfs_max(READ, PROG)];
lfs_block_t block;
// write block 0
block = 0;
cfg->erase(cfg, block) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (block+i+j) % 251;
}
cfg->prog(cfg, block, i, buffer, PROG) => 0;
@@ -106,19 +106,19 @@ code = '''
// read block 0
block = 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
// write block n-1
block = cfg->block_count-1;
cfg->erase(cfg, block) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (block+i+j) % 251;
}
cfg->prog(cfg, block, i, buffer, PROG) => 0;
@@ -126,21 +126,21 @@ code = '''
// read block n-1
block = cfg->block_count-1;
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
// read block 0 again
block = 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
'''
@@ -149,26 +149,26 @@ code = '''
defines.READ = ['READ_SIZE', 'BLOCK_SIZE']
defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE']
code = '''
uint8_t buffer[lfs2_max(READ, PROG)];
uint8_t buffer[lfs_max(READ, PROG)];
// write/read every power of 2
lfs2_block_t block = 1;
lfs_block_t block = 1;
while (block < cfg->block_count) {
// write
cfg->erase(cfg, block) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (block+i+j) % 251;
}
cfg->prog(cfg, block, i, buffer, PROG) => 0;
}
// read
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
@@ -179,11 +179,11 @@ code = '''
block = 1;
while (block < cfg->block_count) {
// read
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
@@ -195,31 +195,31 @@ code = '''
defines.READ = ['READ_SIZE', 'BLOCK_SIZE']
defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE']
code = '''
uint8_t buffer[lfs2_max(READ, PROG)];
uint8_t buffer[lfs_max(READ, PROG)];
// write/read every fibonacci number on our device
lfs2_block_t block = 1;
lfs2_block_t block_ = 1;
lfs_block_t block = 1;
lfs_block_t block_ = 1;
while (block < cfg->block_count) {
// write
cfg->erase(cfg, block) => 0;
for (lfs2_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs2_off_t j = 0; j < PROG; j++) {
for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) {
for (lfs_off_t j = 0; j < PROG; j++) {
buffer[j] = (block+i+j) % 251;
}
cfg->prog(cfg, block, i, buffer, PROG) => 0;
}
// read
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
lfs2_block_t nblock = block + block_;
lfs_block_t nblock = block + block_;
block_ = block;
block = nblock;
}
@@ -229,15 +229,15 @@ code = '''
block_ = 1;
while (block < cfg->block_count) {
// read
for (lfs2_off_t i = 0; i < cfg->block_size; i += READ) {
for (lfs_off_t i = 0; i < cfg->block_size; i += READ) {
cfg->read(cfg, block, i, buffer, READ) => 0;
for (lfs2_off_t j = 0; j < READ; j++) {
LFS2_ASSERT(buffer[j] == (block+i+j) % 251);
for (lfs_off_t j = 0; j < READ; j++) {
LFS_ASSERT(buffer[j] == (block+i+j) % 251);
}
}
lfs2_block_t nblock = block + block_;
lfs_block_t nblock = block + block_;
block_ = block;
block = nblock;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,92 +10,92 @@ code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 20
char path[1024];
lfs2_size_t size;
lfs_size_t size;
sprintf(path, "hi0"); size = 20;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi2 20
sprintf(path, "hi2"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi3 20
sprintf(path, "hi3"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// write hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi0 20
sprintf(path, "hi0"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi2 20
sprintf(path, "hi2"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 20
sprintf(path, "hi3"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_shrink]
@@ -103,92 +103,92 @@ code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 20
char path[1024];
lfs2_size_t size;
lfs_size_t size;
sprintf(path, "hi0"); size = 20;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi2 20
sprintf(path, "hi2"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi3 20
sprintf(path, "hi3"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// write hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi0 20
sprintf(path, "hi0"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi2 20
sprintf(path, "hi2"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 20
sprintf(path, "hi3"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_spill]
@@ -196,76 +196,76 @@ code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200
char path[1024];
lfs2_size_t size;
lfs_size_t size;
sprintf(path, "hi0"); size = 200;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi0 200
sprintf(path, "hi0"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_push_spill]
@@ -273,92 +273,92 @@ code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200
char path[1024];
lfs2_size_t size;
lfs_size_t size;
sprintf(path, "hi0"); size = 200;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// write hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi0 200
sprintf(path, "hi0"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_push_spill_two]
@@ -366,107 +366,107 @@ code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200
char path[1024];
lfs2_size_t size;
lfs_size_t size;
sprintf(path, "hi0"); size = 200;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi4 200
sprintf(path, "hi4"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi1 20
sprintf(path, "hi1"); size = 20;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// write hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// read hi0 200
sprintf(path, "hi0"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi4 200
sprintf(path, "hi4"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_drop]
@@ -474,169 +474,169 @@ code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200
char path[1024];
lfs2_size_t size;
lfs_size_t size;
sprintf(path, "hi0"); size = 200;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi1 200
sprintf(path, "hi1"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
// write hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_close(&lfs, &file) => 0;
lfs2_remove(&lfs2, "hi1") => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "hi1", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "hi1") => 0;
struct lfs_info info;
lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT;
// read hi0 200
sprintf(path, "hi0"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi2 200
sprintf(path, "hi2"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_remove(&lfs2, "hi2") => 0;
lfs2_stat(&lfs2, "hi2", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "hi2") => 0;
lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT;
// read hi0 200
sprintf(path, "hi0"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read hi3 200
sprintf(path, "hi3"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_remove(&lfs2, "hi3") => 0;
lfs2_stat(&lfs2, "hi3", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "hi3") => 0;
lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT;
// read hi0 200
sprintf(path, "hi0"); size = 200;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_remove(&lfs2, "hi0") => 0;
lfs2_stat(&lfs2, "hi0", &info) => LFS2_ERR_NOENT;
lfs_remove(&lfs, "hi0") => 0;
lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_create_too_big]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
char path[1024];
memset(path, 'm', 200);
path[200] = '\0';
lfs2_size_t size = 400;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_size_t size = 400;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024];
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
size = 400;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
uint8_t rbuffer[1024];
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_entries_resize_too_big]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
char path[1024];
memset(path, 'm', 200);
path[200] = '\0';
lfs2_size_t size = 40;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_size_t size = 40;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024];
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
size = 40;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
uint8_t rbuffer[1024];
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
size = 400;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
size = 400;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
memcmp(rbuffer, wbuffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -4,303 +4,303 @@
# invalid pointer tests (outside of block_count)
[cases.test_evil_invalid_tail_pointer]
defines.TAIL_TYPE = ['LFS2_TYPE_HARDTAIL', 'LFS2_TYPE_SOFTTAIL']
defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL']
defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// change tail-pointer to invalid pointers
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8),
(lfs2_block_t[2]){
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
(lfs_block_t[2]){
(INVALSET & 0x1) ? 0xcccccccc : 0,
(INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
[cases.test_evil_invalid_dir_pointer]
defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// make a dir
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "dir_here") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "dir_here") => 0;
lfs_unmount(&lfs) => 0;
// change the dir pointer to be invalid
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our directory
uint8_t buffer[1024];
lfs2_dir_get(&lfs2, &mdir,
LFS2_MKTAG(0x700, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("dir_here")), buffer)
=> LFS2_MKTAG(LFS2_TYPE_DIR, 1, strlen("dir_here"));
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer)
=> LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here"));
assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0);
// change dir pointer
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, 8),
(lfs2_block_t[2]){
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8),
(lfs_block_t[2]){
(INVALSET & 0x1) ? 0xcccccccc : 0,
(INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_deinit(&lfs) => 0;
// test that accessing our bad dir fails, note there's a number
// of ways to access the dir, some can fail, but some don't
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "dir_here", &info) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dir_here", &info) => 0;
assert(strcmp(info.name, "dir_here") == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "dir_here") => LFS2_ERR_CORRUPT;
lfs2_stat(&lfs2, "dir_here/file_here", &info) => LFS2_ERR_CORRUPT;
lfs2_dir_open(&lfs2, &dir, "dir_here/dir_here") => LFS2_ERR_CORRUPT;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "dir_here/file_here",
LFS2_O_RDONLY) => LFS2_ERR_CORRUPT;
lfs2_file_open(&lfs2, &file, "dir_here/file_here",
LFS2_O_WRONLY | LFS2_O_CREAT) => LFS2_ERR_CORRUPT;
lfs2_unmount(&lfs2) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT;
lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT;
lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT;
lfs_file_t file;
lfs_file_open(&lfs, &file, "dir_here/file_here",
LFS_O_RDONLY) => LFS_ERR_CORRUPT;
lfs_file_open(&lfs, &file, "dir_here/file_here",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT;
lfs_unmount(&lfs) => 0;
'''
[cases.test_evil_invalid_file_pointer]
in = "lfs2.c"
in = "lfs.c"
defines.SIZE = [10, 1000, 100000] # faked file size
code = '''
// create littlefs
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// make a file
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "file_here",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// change the file pointer to be invalid
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file
uint8_t buffer[1024];
lfs2_dir_get(&lfs2, &mdir,
LFS2_MKTAG(0x700, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer)
=> LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here"));
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
=> LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here"));
assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
// change file pointer
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz)),
&(struct lfs2_ctz){0xcccccccc, lfs2_tole32(SIZE)}})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)),
&(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0;
lfs_deinit(&lfs) => 0;
// test that accessing our bad file fails, note there's a number
// of ways to access the dir, some can fail, but some don't
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "file_here", &info) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT;
lfs_file_close(&lfs, &file) => 0;
// any allocs that traverse CTZ must unfortunately must fail
if (SIZE > 2*BLOCK_SIZE) {
lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT;
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_evil_invalid_ctz_pointer] # invalid pointer in CTZ skip-list test
defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE']
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// make a file
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "file_here",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < SIZE; i++) {
char c = 'c';
lfs2_file_write(&lfs2, &file, &c, 1) => 1;
lfs_file_write(&lfs, &file, &c, 1) => 1;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// change pointer in CTZ skip-list to be invalid
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file and get our CTZ structure
uint8_t buffer[4*BLOCK_SIZE];
lfs2_dir_get(&lfs2, &mdir,
LFS2_MKTAG(0x700, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_NAME, 1, strlen("file_here")), buffer)
=> LFS2_MKTAG(LFS2_TYPE_REG, 1, strlen("file_here"));
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
=> LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here"));
assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0);
struct lfs2_ctz ctz;
lfs2_dir_get(&lfs2, &mdir,
LFS2_MKTAG(0x700, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_STRUCT, 1, sizeof(struct lfs2_ctz)), &ctz)
=> LFS2_MKTAG(LFS2_TYPE_CTZSTRUCT, 1, sizeof(struct lfs2_ctz));
lfs2_ctz_fromle32(&ctz);
struct lfs_ctz ctz;
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz)
=> LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz));
lfs_ctz_fromle32(&ctz);
// rewrite block to contain bad pointer
uint8_t bbuffer[BLOCK_SIZE];
cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
uint32_t bad = lfs2_tole32(0xcccccccc);
uint32_t bad = lfs_tole32(0xcccccccc);
memcpy(&bbuffer[0], &bad, sizeof(bad));
memcpy(&bbuffer[4], &bad, sizeof(bad));
cfg->erase(cfg, ctz.head) => 0;
cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_deinit(&lfs) => 0;
// test that accessing our bad file fails, note there's a number
// of ways to access the dir, some can fail, but some don't
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "file_here", &info) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfs2_file_open(&lfs2, &file, "file_here", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, SIZE) => LFS2_ERR_CORRUPT;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT;
lfs_file_close(&lfs, &file) => 0;
// any allocs that traverse CTZ must unfortunately must fail
if (SIZE > 2*BLOCK_SIZE) {
lfs2_mkdir(&lfs2, "dir_here") => LFS2_ERR_CORRUPT;
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_evil_invalid_gstate_pointer]
defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create an invalid gstate
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_fs_prepmove(&lfs2, 1, (lfs2_block_t [2]){
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
(INVALSET & 0x1) ? 0xcccccccc : 0,
(INVALSET & 0x2) ? 0xcccccccc : 0});
lfs2_dir_commit(&lfs2, &mdir, NULL, 0) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
// mount may not fail, but our first alloc should fail when
// we try to fix the gstate
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "should_fail") => LFS2_ERR_CORRUPT;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT;
lfs_unmount(&lfs) => 0;
'''
# cycle detection/recovery tests
[cases.test_evil_mdir_loop] # metadata-pair threaded-list loop test
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// change tail-pointer to point to ourself
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8),
(lfs2_block_t[2]){0, 1}})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
(lfs_block_t[2]){0, 1}})) => 0;
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
[cases.test_evil_mdir_loop2] # metadata-pair threaded-list 2-length loop test
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs with child dir
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "child") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
// find child
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_block_t pair[2];
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_dir_get(&lfs2, &mdir,
LFS2_MKTAG(0x7ff, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
=> LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair));
lfs2_pair_fromle32(pair);
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
=> LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair));
lfs_pair_fromle32(pair);
// change tail-pointer to point to root
lfs2_dir_fetch(&lfs2, &mdir, pair) => 0;
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8),
(lfs2_block_t[2]){0, 1}})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_dir_fetch(&lfs, &mdir, pair) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8),
(lfs_block_t[2]){0, 1}})) => 0;
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
[cases.test_evil_mdir_loop_child] # metadata-pair threaded-list 1-length child loop test
in = "lfs2.c"
in = "lfs.c"
code = '''
// create littlefs with child dir
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "child") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
// find child
lfs2_init(&lfs2, cfg) => 0;
lfs2_mdir_t mdir;
lfs2_block_t pair[2];
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_dir_get(&lfs2, &mdir,
LFS2_MKTAG(0x7ff, 0x3ff, 0),
LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
=> LFS2_MKTAG(LFS2_TYPE_DIRSTRUCT, 1, sizeof(pair));
lfs2_pair_fromle32(pair);
lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x7ff, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair)
=> LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair));
lfs_pair_fromle32(pair);
// change tail-pointer to point to ourself
lfs2_dir_fetch(&lfs2, &mdir, pair) => 0;
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_dir_fetch(&lfs, &mdir, pair) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0;
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''

View File

@@ -4,50 +4,50 @@ defines.ERASE_CYCLES = 10
defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
defines.BADBLOCK_BEHAVIOR = [
'LFS2_EMUBD_BADBLOCK_PROGERROR',
'LFS2_EMUBD_BADBLOCK_ERASEERROR',
'LFS2_EMUBD_BADBLOCK_READERROR',
'LFS2_EMUBD_BADBLOCK_PROGNOOP',
'LFS2_EMUBD_BADBLOCK_ERASENOOP',
'LFS_EMUBD_BADBLOCK_PROGERROR',
'LFS_EMUBD_BADBLOCK_ERASEERROR',
'LFS_EMUBD_BADBLOCK_READERROR',
'LFS_EMUBD_BADBLOCK_PROGNOOP',
'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.FILES = 10
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "roadrunner") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0;
uint32_t cycle = 0;
while (true) {
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "roadrunner/test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS2_ERR_NOSPC) {
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs2_unmount(&lfs2) => 0;
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) {
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS2_ERR_NOSPC) {
lfs2_unmount(&lfs2) => 0;
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
@@ -57,37 +57,37 @@ code = '''
char path[1024];
sprintf(path, "roadrunner/test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
char r;
lfs2_file_read(&lfs2, &file, &r, 1) => 1;
lfs_file_read(&lfs, &file, &r, 1) => 1;
assert(r == c);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
cycle += 1;
}
exhausted:
// should still be readable
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
char path[1024];
sprintf(path, "roadrunner/test%d", i);
struct lfs2_info info;
lfs2_stat(&lfs2, path, &info) => 0;
struct lfs_info info;
lfs_stat(&lfs, path, &info) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
LFS2_WARN("completed %d cycles", cycle);
LFS_WARN("completed %d cycles", cycle);
'''
# test running a filesystem to exhaustion
@@ -97,47 +97,47 @@ defines.ERASE_CYCLES = 10
defines.ERASE_COUNT = 256 # small bd so test runs faster
defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
defines.BADBLOCK_BEHAVIOR = [
'LFS2_EMUBD_BADBLOCK_PROGERROR',
'LFS2_EMUBD_BADBLOCK_ERASEERROR',
'LFS2_EMUBD_BADBLOCK_READERROR',
'LFS2_EMUBD_BADBLOCK_PROGNOOP',
'LFS2_EMUBD_BADBLOCK_ERASENOOP',
'LFS_EMUBD_BADBLOCK_PROGERROR',
'LFS_EMUBD_BADBLOCK_ERASEERROR',
'LFS_EMUBD_BADBLOCK_READERROR',
'LFS_EMUBD_BADBLOCK_PROGNOOP',
'LFS_EMUBD_BADBLOCK_ERASENOOP',
]
defines.FILES = 10
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
uint32_t cycle = 0;
while (true) {
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS2_ERR_NOSPC) {
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs2_unmount(&lfs2) => 0;
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) {
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS2_ERR_NOSPC) {
lfs2_unmount(&lfs2) => 0;
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
@@ -147,37 +147,37 @@ code = '''
char path[1024];
sprintf(path, "test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
char r;
lfs2_file_read(&lfs2, &file, &r, 1) => 1;
lfs_file_read(&lfs, &file, &r, 1) => 1;
assert(r == c);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
cycle += 1;
}
exhausted:
// should still be readable
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
char path[1024];
struct lfs2_info info;
struct lfs_info info;
sprintf(path, "test%d", i);
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
LFS2_WARN("completed %d cycles", cycle);
LFS_WARN("completed %d cycles", cycle);
'''
# These are a sort of high-level litmus test for wear-leveling. One definition
@@ -196,47 +196,47 @@ code = '''
const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
for (int run = 0; run < 2; run++) {
for (lfs2_block_t b = 0; b < BLOCK_COUNT; b++) {
lfs2_emubd_setwear(cfg, b,
for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
lfs_emubd_setwear(cfg, b,
(b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
}
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "roadrunner") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0;
uint32_t cycle = 0;
while (true) {
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "roadrunner/test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS2_ERR_NOSPC) {
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs2_unmount(&lfs2) => 0;
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) {
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS2_ERR_NOSPC) {
lfs2_unmount(&lfs2) => 0;
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
@@ -246,43 +246,43 @@ code = '''
char path[1024];
sprintf(path, "roadrunner/test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
char r;
lfs2_file_read(&lfs2, &file, &r, 1) => 1;
lfs_file_read(&lfs, &file, &r, 1) => 1;
assert(r == c);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
cycle += 1;
}
exhausted:
// should still be readable
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
char path[1024];
struct lfs2_info info;
struct lfs_info info;
sprintf(path, "roadrunner/test%d", i);
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
run_cycles[run] = cycle;
LFS2_WARN("completed %d blocks %d cycles",
LFS_WARN("completed %d blocks %d cycles",
run_block_count[run], run_cycles[run]);
}
// check we increased the lifetime by 2x with ~10% error
LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
'''
# wear-level test + expanding superblock
@@ -296,44 +296,44 @@ code = '''
const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
for (int run = 0; run < 2; run++) {
for (lfs2_block_t b = 0; b < BLOCK_COUNT; b++) {
lfs2_emubd_setwear(cfg, b,
for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
lfs_emubd_setwear(cfg, b,
(b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
}
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
uint32_t cycle = 0;
while (true) {
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS2_ERR_NOSPC) {
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs2_unmount(&lfs2) => 0;
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) {
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS2_ERR_NOSPC) {
lfs2_unmount(&lfs2) => 0;
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
@@ -343,43 +343,43 @@ code = '''
char path[1024];
sprintf(path, "test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
char r;
lfs2_file_read(&lfs2, &file, &r, 1) => 1;
lfs_file_read(&lfs, &file, &r, 1) => 1;
assert(r == c);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
cycle += 1;
}
exhausted:
// should still be readable
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
char path[1024];
struct lfs2_info info;
struct lfs_info info;
sprintf(path, "test%d", i);
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
run_cycles[run] = cycle;
LFS2_WARN("completed %d blocks %d cycles",
LFS_WARN("completed %d blocks %d cycles",
run_block_count[run], run_cycles[run]);
}
// check we increased the lifetime by 2x with ~10% error
LFS2_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
'''
# test that we wear blocks roughly evenly
@@ -391,42 +391,42 @@ defines.CYCLES = 100
defines.FILES = 10
if = 'BLOCK_CYCLES < CYCLES/10'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "roadrunner") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0;
uint32_t cycle = 0;
while (cycle < CYCLES) {
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "roadrunner/test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
lfs2_ssize_t res = lfs2_file_write(&lfs2, &file, &c, 1);
assert(res == 1 || res == LFS2_ERR_NOSPC);
if (res == LFS2_ERR_NOSPC) {
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
lfs2_unmount(&lfs2) => 0;
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) {
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
int err = lfs2_file_close(&lfs2, &file);
assert(err == 0 || err == LFS2_ERR_NOSPC);
if (err == LFS2_ERR_NOSPC) {
lfs2_unmount(&lfs2) => 0;
int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
@@ -436,45 +436,45 @@ code = '''
char path[1024];
sprintf(path, "roadrunner/test%d", i);
uint32_t prng = cycle * i;
lfs2_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (TEST_PRNG(&prng) % 26);
char r;
lfs2_file_read(&lfs2, &file, &r, 1) => 1;
lfs_file_read(&lfs, &file, &r, 1) => 1;
assert(r == c);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
cycle += 1;
}
exhausted:
// should still be readable
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
char path[1024];
struct lfs2_info info;
struct lfs_info info;
sprintf(path, "roadrunner/test%d", i);
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
LFS2_WARN("completed %d cycles", cycle);
LFS_WARN("completed %d cycles", cycle);
// check the wear on our block device
lfs2_emubd_wear_t minwear = -1;
lfs2_emubd_wear_t totalwear = 0;
lfs2_emubd_wear_t maxwear = 0;
lfs_emubd_wear_t minwear = -1;
lfs_emubd_wear_t totalwear = 0;
lfs_emubd_wear_t maxwear = 0;
// skip 0 and 1 as superblock movement is intentionally avoided
for (lfs2_block_t b = 2; b < BLOCK_COUNT; b++) {
lfs2_emubd_wear_t wear = lfs2_emubd_wear(cfg, b);
for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b);
printf("%08x: wear %d\n", b, wear);
assert(wear >= 0);
if (wear < minwear) {
@@ -485,21 +485,21 @@ exhausted:
}
totalwear += wear;
}
lfs2_emubd_wear_t avgwear = totalwear / BLOCK_COUNT;
LFS2_WARN("max wear: %d cycles", maxwear);
LFS2_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT);
LFS2_WARN("min wear: %d cycles", minwear);
lfs_emubd_wear_t avgwear = totalwear / BLOCK_COUNT;
LFS_WARN("max wear: %d cycles", maxwear);
LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT);
LFS_WARN("min wear: %d cycles", minwear);
// find standard deviation^2
lfs2_emubd_wear_t dev2 = 0;
for (lfs2_block_t b = 2; b < BLOCK_COUNT; b++) {
lfs2_emubd_wear_t wear = lfs2_emubd_wear(cfg, b);
lfs_emubd_wear_t dev2 = 0;
for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b);
assert(wear >= 0);
lfs2_emubd_swear_t diff = wear - avgwear;
lfs_emubd_swear_t diff = wear - avgwear;
dev2 += diff*diff;
}
dev2 /= totalwear;
LFS2_WARN("std dev^2: %d", dev2);
LFS_WARN("std dev^2: %d", dev2);
assert(dev2 < 8);
'''

View File

@@ -1,539 +1,516 @@
[cases.test_files_simple]
defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "hello",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_size_t size = strlen("Hello World!")+1;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_size_t size = strlen("Hello World!")+1;
uint8_t buffer[1024];
strcpy((char*)buffer, "Hello World!");
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "hello", LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(strcmp((char*)buffer, "Hello World!") == 0);
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_large]
defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "avacado",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t prng = 1;
uint8_t buffer[1024];
for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_rewrite]
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
uint8_t buffer[1024];
lfs2_file_open(&lfs2, &file, "avacado",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE1;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// rewrite
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0;
prng = 2;
for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => lfs2_max(SIZE1, SIZE2);
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2);
prng = 2;
for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
if (SIZE1 > SIZE2) {
prng = 1;
for (lfs2_size_t b = 0; b < SIZE2; b++) {
for (lfs_size_t b = 0; b < SIZE2; b++) {
TEST_PRNG(&prng);
}
for (lfs2_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_append]
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
uint8_t buffer[1024];
lfs2_file_open(&lfs2, &file, "avacado",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE1;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// append
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_APPEND) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0;
prng = 2;
for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE1 + SIZE2;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1 + SIZE2;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
prng = 2;
for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_truncate]
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
defines.CHUNKSIZE = [31, 16, 1]
defines.INLINE_MAX = [0, -1, 8]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
uint8_t buffer[1024];
lfs2_file_open(&lfs2, &file, "avacado",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint32_t prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE1;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE1-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// truncate
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_TRUNC) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
prng = 2;
for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// read
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE2;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE2;
prng = 2;
for (lfs2_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE2-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_reentrant_write]
defines.SIZE = [32, 0, 7, 2049]
defines.CHUNKSIZE = [31, 16, 65]
defines.INLINE_MAX = [0, -1, 8]
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
lfs2_file_t file;
lfs_file_t file;
uint8_t buffer[1024];
err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY);
assert(err == LFS2_ERR_NOENT || err == 0);
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0);
if (err == 0) {
// can only be 0 (new file) or full size
lfs2_size_t size = lfs2_file_size(&lfs2, &file);
lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size == 0 || size == SIZE);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
// write
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint32_t prng = 1;
for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_reentrant_write_sync]
defines = [
# append (O(n))
{MODE='LFS2_O_APPEND',
SIZE=[32, 0, 7, 2049],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
{MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
# truncate (O(n^2))
{MODE='LFS2_O_TRUNC',
SIZE=[32, 0, 7, 200],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
{MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
# rewrite (O(n^2))
{MODE=0,
SIZE=[32, 0, 7, 200],
CHUNKSIZE=[31, 16, 65],
INLINE_MAX=[0, -1, 8]},
{MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
]
reentrant = true
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
lfs2_file_t file;
lfs_file_t file;
uint8_t buffer[1024];
err = lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY);
assert(err == LFS2_ERR_NOENT || err == 0);
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0);
if (err == 0) {
// with syncs we could be any size, but it at least must be valid data
lfs2_size_t size = lfs2_file_size(&lfs2, &file);
lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size <= SIZE);
uint32_t prng = 1;
for (lfs2_size_t i = 0; i < size; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, size-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
// write
lfs2_file_open(&lfs2, &file, "avacado",
LFS2_O_WRONLY | LFS2_O_CREAT | MODE) => 0;
lfs2_size_t size = lfs2_file_size(&lfs2, &file);
lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0;
lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size <= SIZE);
uint32_t prng = 1;
lfs2_size_t skip = (MODE == LFS2_O_APPEND) ? size : 0;
for (lfs2_size_t b = 0; b < skip; b++) {
lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0;
for (lfs_size_t b = 0; b < skip; b++) {
TEST_PRNG(&prng);
}
for (lfs2_size_t i = skip; i < SIZE; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) {
buffer[b] = TEST_PRNG(&prng) & 0xff;
}
lfs2_file_write(&lfs2, &file, buffer, chunk) => chunk;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
lfs_file_sync(&lfs, &file) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// read
lfs2_file_open(&lfs2, &file, "avacado", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE;
prng = 1;
for (lfs2_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs2_size_t chunk = lfs2_min(CHUNKSIZE, SIZE-i);
lfs2_file_read(&lfs2, &file, buffer, chunk) => chunk;
for (lfs2_size_t b = 0; b < chunk; b++) {
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
for (lfs_size_t b = 0; b < chunk; b++) {
assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
}
}
lfs2_file_read(&lfs2, &file, buffer, CHUNKSIZE) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_many]
defines.N = 300
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create N files of 7 bytes
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs2_file_t file;
lfs_file_t file;
char path[1024];
sprintf(path, "file_%03d", i);
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuffer[1024];
lfs2_size_t size = 7;
lfs_size_t size = 7;
sprintf(wbuffer, "Hi %03d", i);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
char rbuffer[1024];
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_many_power_cycle]
defines.N = 300
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create N files of 7 bytes
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs2_file_t file;
lfs_file_t file;
char path[1024];
sprintf(path, "file_%03d", i);
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuffer[1024];
lfs2_size_t size = 7;
lfs_size_t size = 7;
sprintf(wbuffer, "Hi %03d", i);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
char rbuffer[1024];
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_files_many_power_loss]
defines.N = 300
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
// create N files of 7 bytes
for (int i = 0; i < N; i++) {
lfs2_file_t file;
lfs_file_t file;
char path[1024];
sprintf(path, "file_%03d", i);
err = lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY | LFS2_O_CREAT);
err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT);
char wbuffer[1024];
lfs2_size_t size = 7;
lfs_size_t size = 7;
sprintf(wbuffer, "Hi %03d", i);
if ((lfs2_size_t)lfs2_file_size(&lfs2, &file) != size) {
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) {
lfs_file_write(&lfs, &file, wbuffer, size) => size;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
char rbuffer[1024];
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0);
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -3,272 +3,268 @@
defines.SIZE = [10, 100]
defines.FILES = [4, 10, 26]
code = '''
lfs2_t lfs2;
lfs2_file_t files[FILES];
lfs_t lfs;
lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_file_open(&lfs2, &files[j], path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_open(&lfs, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
}
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < FILES; j++) {
lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1;
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1;
}
}
for (int j = 0; j < FILES; j++) {
lfs2_file_close(&lfs2, &files[j]);
lfs_file_close(&lfs, &files[j]);
}
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0;
struct lfs2_info info;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS2_TYPE_DIR);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1;
lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]);
}
}
for (int j = 0; j < FILES; j++) {
lfs2_file_close(&lfs2, &files[j]);
lfs_file_close(&lfs, &files[j]);
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_interspersed_remove_files]
defines.SIZE = [10, 100]
defines.FILES = [4, 10, 26]
code = '''
lfs2_t lfs2;
lfs_t lfs;
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
for (int i = 0; i < SIZE; i++) {
lfs2_file_write(&lfs2, &file, &alphas[j], 1) => 1;
lfs_file_write(&lfs, &file, &alphas[j], 1) => 1;
}
lfs2_file_close(&lfs2, &file);
lfs_file_close(&lfs, &file);
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int j = 0; j < FILES; j++) {
lfs2_file_write(&lfs2, &file, (const void*)"~", 1) => 1;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1;
lfs_file_sync(&lfs, &file) => 0;
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_remove(&lfs2, path) => 0;
lfs_remove(&lfs, path) => 0;
}
lfs2_file_close(&lfs2, &file);
lfs_file_close(&lfs, &file);
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0;
struct lfs2_info info;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS2_TYPE_DIR);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS2_TYPE_DIR);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "zzz") == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == FILES);
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs2_file_open(&lfs2, &file, "zzz", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0;
for (int i = 0; i < FILES; i++) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &file, buffer, 1) => 1;
lfs_file_read(&lfs, &file, buffer, 1) => 1;
assert(buffer[0] == '~');
}
lfs2_file_close(&lfs2, &file);
lfs_file_close(&lfs, &file);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_interspersed_remove_inconveniently]
defines.SIZE = [10, 100]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t files[3];
lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_open(&lfs2, &files[1], "f", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs2_file_open(&lfs2, &files[2], "g", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t files[3];
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < SIZE/2; i++) {
lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1;
lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1;
lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1;
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1;
}
lfs2_remove(&lfs2, "f") => 0;
lfs_remove(&lfs, "f") => 0;
for (int i = 0; i < SIZE/2; i++) {
lfs2_file_write(&lfs2, &files[0], (const void*)"e", 1) => 1;
lfs2_file_write(&lfs2, &files[1], (const void*)"f", 1) => 1;
lfs2_file_write(&lfs2, &files[2], (const void*)"g", 1) => 1;
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1;
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1;
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1;
}
lfs2_file_close(&lfs2, &files[0]);
lfs2_file_close(&lfs2, &files[1]);
lfs2_file_close(&lfs2, &files[2]);
lfs_file_close(&lfs, &files[0]);
lfs_file_close(&lfs, &files[1]);
lfs_file_close(&lfs, &files[2]);
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0;
struct lfs2_info info;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS2_TYPE_DIR);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS2_TYPE_DIR);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "e") == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "g") == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs2_file_open(&lfs2, &files[0], "e", LFS2_O_RDONLY) => 0;
lfs2_file_open(&lfs2, &files[1], "g", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0;
for (int i = 0; i < SIZE; i++) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &files[0], buffer, 1) => 1;
lfs_file_read(&lfs, &files[0], buffer, 1) => 1;
assert(buffer[0] == 'e');
lfs2_file_read(&lfs2, &files[1], buffer, 1) => 1;
lfs_file_read(&lfs, &files[1], buffer, 1) => 1;
assert(buffer[0] == 'g');
}
lfs2_file_close(&lfs2, &files[0]);
lfs2_file_close(&lfs2, &files[1]);
lfs_file_close(&lfs, &files[0]);
lfs_file_close(&lfs, &files[1]);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_interspersed_reentrant_files]
defines.SIZE = [10, 100]
defines.FILES = [4, 10, 26]
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
lfs2_file_t files[FILES];
lfs_t lfs;
lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
int err = lfs2_mount(&lfs2, cfg);
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_file_open(&lfs2, &files[j], path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
lfs_file_open(&lfs, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
}
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < FILES; j++) {
lfs2_ssize_t size = lfs2_file_size(&lfs2, &files[j]);
lfs_ssize_t size = lfs_file_size(&lfs, &files[j]);
assert(size >= 0);
if ((int)size <= i) {
lfs2_file_write(&lfs2, &files[j], &alphas[j], 1) => 1;
lfs2_file_sync(&lfs2, &files[j]) => 0;
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1;
lfs_file_sync(&lfs, &files[j]) => 0;
}
}
}
for (int j = 0; j < FILES; j++) {
lfs2_file_close(&lfs2, &files[j]);
lfs_file_close(&lfs, &files[j]);
}
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "/") => 0;
struct lfs2_info info;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS2_TYPE_DIR);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]);
lfs2_file_open(&lfs2, &files[j], path, LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &files[j], buffer, 1) => 1;
lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]);
}
}
for (int j = 0; j < FILES; j++) {
lfs2_file_close(&lfs2, &files[j]);
lfs_file_close(&lfs, &files[j]);
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,25 @@
[cases.test_orphans_normal]
in = "lfs2.c"
in = "lfs.c"
if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "parent") => 0;
lfs2_mkdir(&lfs2, "parent/orphan") => 0;
lfs2_mkdir(&lfs2, "parent/child") => 0;
lfs2_remove(&lfs2, "parent/orphan") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0;
lfs_remove(&lfs, "parent/orphan") => 0;
lfs_unmount(&lfs) => 0;
// corrupt the child's most recent commit, this should be the update
// to the linked-list entry, which should orphan the orphan. Note this
// makes a lot of assumptions about the remove operation.
lfs2_mount(&lfs2, cfg) => 0;
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "parent/child") => 0;
lfs2_block_t block = dir.m.pair[0];
lfs2_dir_close(&lfs2, &dir) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "parent/child") => 0;
lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
uint8_t buffer[BLOCK_SIZE];
cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = BLOCK_SIZE-1;
@@ -31,195 +31,194 @@ code = '''
cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg->sync(cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs2_fs_size(&lfs2) => 8;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs2_fs_size(&lfs2) => 8;
lfs_mount(&lfs, cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8;
// this mkdir should both create a dir and deorphan, so size
// should be unchanged
lfs2_mkdir(&lfs2, "parent/otherchild") => 0;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs2_stat(&lfs2, "parent/otherchild", &info) => 0;
lfs2_fs_size(&lfs2) => 8;
lfs2_unmount(&lfs2) => 0;
lfs_mkdir(&lfs, "parent/otherchild") => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0;
lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_stat(&lfs2, "parent/orphan", &info) => LFS2_ERR_NOENT;
lfs2_stat(&lfs2, "parent/child", &info) => 0;
lfs2_stat(&lfs2, "parent/otherchild", &info) => 0;
lfs2_fs_size(&lfs2) => 8;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0;
lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0;
'''
# test that we only run deorphan once per power-cycle
[cases.test_orphans_no_orphans]
in = 'lfs2.c'
in = 'lfs.c'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// mark the filesystem as having orphans
lfs2_fs_preporphans(&lfs2, +1) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_dir_commit(&lfs2, &mdir, NULL, 0) => 0;
lfs_fs_preporphans(&lfs, +1) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
// we should have orphans at this state
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
lfs2_unmount(&lfs2) => 0;
assert(lfs_gstate_hasorphans(&lfs.gstate));
lfs_unmount(&lfs) => 0;
// mount
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// we should detect orphans
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
assert(lfs_gstate_hasorphans(&lfs.gstate));
// force consistency
lfs2_fs_forceconsistency(&lfs2) => 0;
lfs_fs_forceconsistency(&lfs) => 0;
// we should no longer have orphans
assert(!lfs2_gstate_hasorphans(&lfs2.gstate));
assert(!lfs_gstate_hasorphans(&lfs.gstate));
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_orphans_one_orphan]
in = 'lfs2.c'
in = 'lfs.c'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// create an orphan
lfs2_mdir_t orphan;
lfs2_alloc_ckpoint(&lfs2);
lfs2_dir_alloc(&lfs2, &orphan) => 0;
lfs2_dir_commit(&lfs2, &orphan, NULL, 0) => 0;
lfs_mdir_t orphan;
lfs_alloc_ack(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
// append our orphan and mark the filesystem as having orphans
lfs2_fs_preporphans(&lfs2, +1) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_pair_tole32(orphan.pair);
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
lfs_fs_preporphans(&lfs, +1) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_pair_tole32(orphan.pair);
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
// we should have orphans at this state
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
lfs2_unmount(&lfs2) => 0;
assert(lfs_gstate_hasorphans(&lfs.gstate));
lfs_unmount(&lfs) => 0;
// mount
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// we should detect orphans
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
assert(lfs_gstate_hasorphans(&lfs.gstate));
// force consistency
lfs2_fs_forceconsistency(&lfs2) => 0;
lfs_fs_forceconsistency(&lfs) => 0;
// we should no longer have orphans
assert(!lfs2_gstate_hasorphans(&lfs2.gstate));
assert(!lfs_gstate_hasorphans(&lfs.gstate));
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# test that we can persist gstate with lfs2_fs_mkconsistent
# test that we can persist gstate with lfs_fs_mkconsistent
[cases.test_orphans_mkconsistent_no_orphans]
in = 'lfs2.c'
in = 'lfs.c'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// mark the filesystem as having orphans
lfs2_fs_preporphans(&lfs2, +1) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_dir_commit(&lfs2, &mdir, NULL, 0) => 0;
lfs_fs_preporphans(&lfs, +1) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0;
// we should have orphans at this state
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
lfs2_unmount(&lfs2) => 0;
assert(lfs_gstate_hasorphans(&lfs.gstate));
lfs_unmount(&lfs) => 0;
// mount
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// we should detect orphans
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
assert(lfs_gstate_hasorphans(&lfs.gstate));
// force consistency
lfs2_fs_mkconsistent(&lfs2) => 0;
lfs_fs_mkconsistent(&lfs) => 0;
// we should no longer have orphans
assert(!lfs2_gstate_hasorphans(&lfs2.gstate));
assert(!lfs_gstate_hasorphans(&lfs.gstate));
// remount
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, cfg) => 0;
// we should still have no orphans
assert(!lfs2_gstate_hasorphans(&lfs2.gstate));
lfs2_unmount(&lfs2) => 0;
assert(!lfs_gstate_hasorphans(&lfs.gstate));
lfs_unmount(&lfs) => 0;
'''
[cases.test_orphans_mkconsistent_one_orphan]
in = 'lfs2.c'
in = 'lfs.c'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// create an orphan
lfs2_mdir_t orphan;
lfs2_alloc_ckpoint(&lfs2);
lfs2_dir_alloc(&lfs2, &orphan) => 0;
lfs2_dir_commit(&lfs2, &orphan, NULL, 0) => 0;
lfs_mdir_t orphan;
lfs_alloc_ack(&lfs);
lfs_dir_alloc(&lfs, &orphan) => 0;
lfs_dir_commit(&lfs, &orphan, NULL, 0) => 0;
// append our orphan and mark the filesystem as having orphans
lfs2_fs_preporphans(&lfs2, +1) => 0;
lfs2_mdir_t mdir;
lfs2_dir_fetch(&lfs2, &mdir, (lfs2_block_t[2]){0, 1}) => 0;
lfs2_pair_tole32(orphan.pair);
lfs2_dir_commit(&lfs2, &mdir, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
lfs_fs_preporphans(&lfs, +1) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_pair_tole32(orphan.pair);
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), orphan.pair})) => 0;
// we should have orphans at this state
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
lfs2_unmount(&lfs2) => 0;
assert(lfs_gstate_hasorphans(&lfs.gstate));
lfs_unmount(&lfs) => 0;
// mount
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// we should detect orphans
assert(lfs2_gstate_hasorphans(&lfs2.gstate));
assert(lfs_gstate_hasorphans(&lfs.gstate));
// force consistency
lfs2_fs_mkconsistent(&lfs2) => 0;
lfs_fs_mkconsistent(&lfs) => 0;
// we should no longer have orphans
assert(!lfs2_gstate_hasorphans(&lfs2.gstate));
assert(!lfs_gstate_hasorphans(&lfs.gstate));
// remount
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, cfg) => 0;
// we should still have no orphans
assert(!lfs2_gstate_hasorphans(&lfs2.gstate));
lfs2_unmount(&lfs2) => 0;
assert(!lfs_gstate_hasorphans(&lfs.gstate));
lfs_unmount(&lfs) => 0;
'''
# reentrant testing for orphans, basically just spam mkdir/remove
[cases.test_orphans_reentrant]
reentrant = true
# TODO fix this case, caused by non-DAG trees
# NOTE the second condition is required
if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT'
if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
defines = [
{FILES=6, DEPTH=1, CYCLES=20},
{FILES=26, DEPTH=1, CYCLES=20},
{FILES=3, DEPTH=3, CYCLES=20},
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
uint32_t prng = 1;
@@ -232,109 +231,43 @@ code = '''
}
// if it does not exist, we create it, else we destroy
struct lfs2_info info;
int res = lfs2_stat(&lfs2, full_path, &info);
if (res == LFS2_ERR_NOENT) {
struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info);
if (res == LFS_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS2_ERR_EXIST);
err = lfs_mkdir(&lfs, path);
assert(!err || err == LFS_ERR_EXIST);
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
}
} else {
// is valid dir?
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS2_ERR_NOTEMPTY);
err = lfs_remove(&lfs, path);
assert(!err || err == LFS_ERR_NOTEMPTY);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT;
}
}
lfs2_unmount(&lfs2) => 0;
'''
# non-reentrant testing for orphans, this is the same as reentrant
# testing, but we test way more states than we could under powerloss
[cases.test_orphans_nonreentrant]
# TODO fix this case, caused by non-DAG trees
# NOTE the second condition is required
if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT'
defines = [
{FILES=6, DEPTH=1, CYCLES=2000},
{FILES=26, DEPTH=1, CYCLES=2000},
{FILES=3, DEPTH=3, CYCLES=2000},
]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
uint32_t prng = 1;
const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
for (unsigned i = 0; i < CYCLES; i++) {
// create random path
char full_path[256];
for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]);
}
// if it does not exist, we create it, else we destroy
struct lfs2_info info;
int res = lfs2_stat(&lfs2, full_path, &info);
if (res == LFS2_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
int err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS2_ERR_EXIST);
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
}
} else {
// is valid dir?
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
int err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS2_ERR_NOTEMPTY);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
}
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

File diff suppressed because it is too large Load Diff

View File

@@ -5,87 +5,87 @@
# only a revision count
[cases.test_powerloss_only_rev]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "notebook") => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "notebook/paper",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "notebook") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "notebook/paper",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
char buffer[256];
strcpy(buffer, "hello");
lfs2_size_t size = strlen("hello");
lfs_size_t size = strlen("hello");
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
char rbuffer[256];
lfs2_file_open(&lfs2, &file, "notebook/paper", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// get pair/rev count
lfs2_mount(&lfs2, cfg) => 0;
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "notebook") => 0;
lfs2_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]};
lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "notebook") => 0;
lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]};
uint32_t rev = dir.m.rev;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
// write just the revision count
uint8_t bbuffer[BLOCK_SIZE];
cfg->read(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0;
memcpy(bbuffer, &(uint32_t){lfs2_tole32(rev+1)}, sizeof(uint32_t));
memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t));
cfg->erase(cfg, pair[1]) => 0;
cfg->prog(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// can read?
lfs2_file_open(&lfs2, &file, "notebook/paper", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// can write?
lfs2_file_open(&lfs2, &file, "notebook/paper",
LFS2_O_WRONLY | LFS2_O_APPEND) => 0;
lfs_file_open(&lfs, &file, "notebook/paper",
LFS_O_WRONLY | LFS_O_APPEND) => 0;
strcpy(buffer, "goodbye");
size = strlen("goodbye");
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_file_open(&lfs2, &file, "notebook/paper", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
strcpy(buffer, "hello");
size = strlen("hello");
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
strcpy(buffer, "goodbye");
size = strlen("goodbye");
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# partial prog, may not be byte in order!
@@ -96,45 +96,45 @@ if = '''
'''
defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"]
defines.BYTE_VALUE = [0x33, 0xcc]
in = "lfs2.c"
in = "lfs.c"
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_mkdir(&lfs2, "notebook") => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "notebook/paper",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "notebook") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "notebook/paper",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
char buffer[256];
strcpy(buffer, "hello");
lfs2_size_t size = strlen("hello");
lfs_size_t size = strlen("hello");
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
char rbuffer[256];
lfs2_file_open(&lfs2, &file, "notebook/paper", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// imitate a partial prog, value should not matter, if littlefs
// doesn't notice the partial prog testbd will assert
// get offset to next prog
lfs2_mount(&lfs2, cfg) => 0;
lfs2_dir_t dir;
lfs2_dir_open(&lfs2, &dir, "notebook") => 0;
lfs2_block_t block = dir.m.pair[0];
lfs2_off_t off = dir.m.off;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "notebook") => 0;
lfs_block_t block = dir.m.pair[0];
lfs_off_t off = dir.m.off;
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
// tweak byte
uint8_t bbuffer[BLOCK_SIZE];
@@ -145,41 +145,41 @@ code = '''
cfg->erase(cfg, block) => 0;
cfg->prog(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// can read?
lfs2_file_open(&lfs2, &file, "notebook/paper", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// can write?
lfs2_file_open(&lfs2, &file, "notebook/paper",
LFS2_O_WRONLY | LFS2_O_APPEND) => 0;
lfs_file_open(&lfs, &file, "notebook/paper",
LFS_O_WRONLY | LFS_O_APPEND) => 0;
strcpy(buffer, "goodbye");
size = strlen("goodbye");
for (int i = 0; i < 5; i++) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_file_open(&lfs2, &file, "notebook/paper", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0;
strcpy(buffer, "hello");
size = strlen("hello");
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
strcpy(buffer, "goodbye");
size = strlen("goodbye");
for (int i = 0; i < 5; i++) {
lfs2_file_read(&lfs2, &file, rbuffer, size) => size;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(memcmp(rbuffer, buffer, size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -4,44 +4,44 @@ defines.ITERATIONS = 20
defines.COUNT = 10
defines.BLOCK_CYCLES = [8, 1]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// fill up filesystem so only ~16 blocks are left
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0;
uint8_t buffer[512];
memset(buffer, 0, 512);
while (BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) {
lfs2_file_write(&lfs2, &file, buffer, 512) => 512;
while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) {
lfs_file_write(&lfs, &file, buffer, 512) => 512;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// make a child dir to use in bounded space
lfs2_mkdir(&lfs2, "child") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (unsigned j = 0; j < ITERATIONS; j++) {
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_dir_t dir;
struct lfs2_info info;
lfs2_dir_open(&lfs2, &dir, "child") => 0;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
if (j == (unsigned)ITERATIONS-1) {
break;
@@ -50,31 +50,31 @@ code = '''
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_remove(&lfs2, path) => 0;
lfs_remove(&lfs, path) => 0;
}
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_dir_t dir;
struct lfs2_info info;
lfs2_dir_open(&lfs2, &dir, "child") => 0;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_remove(&lfs2, path) => 0;
lfs_remove(&lfs, path) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_relocations_outdated_head]
@@ -82,87 +82,87 @@ defines.ITERATIONS = 20
defines.COUNT = 10
defines.BLOCK_CYCLES = [8, 1]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// fill up filesystem so only ~16 blocks are left
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "padding", LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0;
uint8_t buffer[512];
memset(buffer, 0, 512);
while (BLOCK_COUNT - lfs2_fs_size(&lfs2) > 16) {
lfs2_file_write(&lfs2, &file, buffer, 512) => 512;
while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) {
lfs_file_write(&lfs, &file, buffer, 512) => 512;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
// make a child dir to use in bounded space
lfs2_mkdir(&lfs2, "child") => 0;
lfs2_unmount(&lfs2) => 0;
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (unsigned j = 0; j < ITERATIONS; j++) {
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_file_open(&lfs2, &file, path, LFS2_O_CREAT | LFS2_O_WRONLY) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_dir_t dir;
struct lfs2_info info;
lfs2_dir_open(&lfs2, &dir, "child") => 0;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
info.size => 0;
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file, "hi", 2) => 2;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hi", 2) => 2;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs2_dir_rewind(&lfs2, &dir) => 0;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_rewind(&lfs, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
info.size => 2;
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_file_open(&lfs2, &file, path, LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file, "hi", 2) => 2;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hi", 2) => 2;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs2_dir_rewind(&lfs2, &dir) => 0;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_rewind(&lfs, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs2_dir_read(&lfs2, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
info.size => 2;
}
lfs2_dir_read(&lfs2, &dir, &info) => 0;
lfs2_dir_close(&lfs2, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs2_remove(&lfs2, path) => 0;
lfs_remove(&lfs, path) => 0;
}
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# reentrant testing for relocations, this is the same as the
@@ -179,11 +179,11 @@ defines = [
{FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1},
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
uint32_t prng = 1;
@@ -196,44 +196,44 @@ code = '''
}
// if it does not exist, we create it, else we destroy
struct lfs2_info info;
int res = lfs2_stat(&lfs2, full_path, &info);
if (res == LFS2_ERR_NOENT) {
struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info);
if (res == LFS_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS2_ERR_EXIST);
err = lfs_mkdir(&lfs, path);
assert(!err || err == LFS_ERR_EXIST);
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
}
} else {
// is valid dir?
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty
for (unsigned d = DEPTH-1; d+1 > 0; d--) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS2_ERR_NOTEMPTY);
err = lfs_remove(&lfs, path);
assert(!err || err == LFS_ERR_NOTEMPTY);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT;
}
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# reentrant testing for relocations, but now with random renames!
@@ -248,11 +248,11 @@ defines = [
{FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1},
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
uint32_t prng = 1;
@@ -265,30 +265,30 @@ code = '''
}
// if it does not exist, we create it, else we destroy
struct lfs2_info info;
int res = lfs2_stat(&lfs2, full_path, &info);
assert(!res || res == LFS2_ERR_NOENT);
if (res == LFS2_ERR_NOENT) {
struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info);
assert(!res || res == LFS_ERR_NOENT);
if (res == LFS_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS2_ERR_EXIST);
err = lfs_mkdir(&lfs, path);
assert(!err || err == LFS_ERR_EXIST);
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
}
} else {
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
// create new random path
char new_path[256];
@@ -297,9 +297,9 @@ code = '''
}
// if new path does not exist, rename, otherwise destroy
res = lfs2_stat(&lfs2, new_path, &info);
assert(!res || res == LFS2_ERR_NOENT);
if (res == LFS2_ERR_NOENT) {
res = lfs_stat(&lfs, new_path, &info);
assert(!res || res == LFS_ERR_NOENT);
if (res == LFS_ERR_NOENT) {
// stop once some dir is renamed
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
@@ -307,8 +307,8 @@ code = '''
path[2*d+2] = '\0';
strcpy(&path[128+2*d], &new_path[2*d]);
path[128+2*d+2] = '\0';
err = lfs2_rename(&lfs2, path, path+128);
assert(!err || err == LFS2_ERR_NOTEMPTY);
err = lfs_rename(&lfs, path, path+128);
assert(!err || err == LFS_ERR_NOTEMPTY);
if (!err) {
strcpy(path, path+128);
}
@@ -318,12 +318,12 @@ code = '''
char path[1024];
strcpy(path, new_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
lfs_stat(&lfs, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
assert(info.type == LFS_TYPE_DIR);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT;
} else {
// try to delete path in reverse order,
// ignore if dir is not empty
@@ -331,181 +331,13 @@ code = '''
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS2_ERR_NOTEMPTY);
err = lfs_remove(&lfs, path);
assert(!err || err == LFS_ERR_NOTEMPTY);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT;
}
}
}
lfs2_unmount(&lfs2) => 0;
'''
# non-reentrant testing for orphans, this is the same as reentrant
# testing, but we test way more states than we could under powerloss
[cases.test_relocations_nonreentrant]
# TODO fix this case, caused by non-DAG trees
# NOTE the second condition is required
if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT'
defines = [
{FILES=6, DEPTH=1, CYCLES=2000, BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=2000, BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=2000, BLOCK_CYCLES=1},
]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
uint32_t prng = 1;
const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
for (unsigned i = 0; i < CYCLES; i++) {
// create random path
char full_path[256];
for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]);
}
// if it does not exist, we create it, else we destroy
struct lfs2_info info;
int res = lfs2_stat(&lfs2, full_path, &info);
if (res == LFS2_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
int err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS2_ERR_EXIST);
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
}
} else {
// is valid dir?
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty
for (unsigned d = DEPTH-1; d+1 > 0; d--) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
int err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS2_ERR_NOTEMPTY);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
}
}
lfs2_unmount(&lfs2) => 0;
'''
# non-reentrant testing for relocations, but now with random renames!
[cases.test_relocations_nonreentrant_renames]
# TODO fix this case, caused by non-DAG trees
# NOTE the second condition is required
if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT'
defines = [
{FILES=6, DEPTH=1, CYCLES=2000, BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=2000, BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=2000, BLOCK_CYCLES=1},
]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
uint32_t prng = 1;
const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
for (unsigned i = 0; i < CYCLES; i++) {
// create random path
char full_path[256];
for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]);
}
// if it does not exist, we create it, else we destroy
struct lfs2_info info;
int res = lfs2_stat(&lfs2, full_path, &info);
assert(!res || res == LFS2_ERR_NOENT);
if (res == LFS2_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
int err = lfs2_mkdir(&lfs2, path);
assert(!err || err == LFS2_ERR_EXIST);
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
}
} else {
assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
// create new random path
char new_path[256];
for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&new_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]);
}
// if new path does not exist, rename, otherwise destroy
res = lfs2_stat(&lfs2, new_path, &info);
assert(!res || res == LFS2_ERR_NOENT);
if (res == LFS2_ERR_NOENT) {
// stop once some dir is renamed
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(&path[2*d], &full_path[2*d]);
path[2*d+2] = '\0';
strcpy(&path[128+2*d], &new_path[2*d]);
path[128+2*d+2] = '\0';
int err = lfs2_rename(&lfs2, path, path+128);
assert(!err || err == LFS2_ERR_NOTEMPTY);
if (!err) {
strcpy(path, path+128);
}
}
for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, new_path);
path[2*d+2] = '\0';
lfs2_stat(&lfs2, path, &info) => 0;
assert(strcmp(info.name, &path[2*d+1]) == 0);
assert(info.type == LFS2_TYPE_DIR);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
} else {
// try to delete path in reverse order,
// ignore if dir is not empty
for (unsigned d = DEPTH-1; d+1 > 0; d--) {
char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
int err = lfs2_remove(&lfs2, path);
assert(!err || err == LFS2_ERR_NOTEMPTY);
}
lfs2_stat(&lfs2, full_path, &info) => LFS2_ERR_NOENT;
}
}
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -10,66 +10,66 @@ defines = [
{COUNT=4, SKIP=2},
]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
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;
size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size);
lfs_file_write(&lfs, &file, buffer, size);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0;
lfs2_soff_t pos = -1;
lfs_soff_t pos = -1;
size = strlen("kittycatcat");
for (int i = 0; i < SKIP; i++) {
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs2_file_tell(&lfs2, &file);
pos = lfs_file_tell(&lfs, &file);
}
assert(pos >= 0);
lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_rewind(&lfs2, &file) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_rewind(&lfs, &file) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file, size, LFS2_SEEK_CUR) => 3*size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_CUR) => pos;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
size = lfs2_file_size(&lfs2, &file);
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size;
size = lfs_file_size(&lfs, &file);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# simple file seek and write
@@ -83,262 +83,115 @@ defines = [
{COUNT=4, SKIP=2},
]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
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;
size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size);
lfs_file_write(&lfs, &file, buffer, size);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
lfs2_soff_t pos = -1;
lfs_soff_t pos = -1;
size = strlen("kittycatcat");
for (int i = 0; i < SKIP; i++) {
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
pos = lfs2_file_tell(&lfs2, &file);
pos = lfs_file_tell(&lfs, &file);
}
assert(pos >= 0);
memcpy(buffer, "doggodogdog", size);
lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0;
lfs2_file_rewind(&lfs2, &file) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_rewind(&lfs, &file) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
lfs2_file_seek(&lfs2, &file, pos, LFS2_SEEK_SET) => pos;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "doggodogdog", size) => 0;
lfs2_file_seek(&lfs2, &file, -size, LFS2_SEEK_END) >= 0 => 1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
size = lfs2_file_size(&lfs2, &file);
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => size;
size = lfs_file_size(&lfs, &file);
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
'''
# boundary seek and reads
[cases.test_seek_boundary_read]
defines.COUNT = 132
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY) => 0;
size = strlen("kittycatcat");
const lfs2_soff_t offsets[] = {
512,
1024-4,
512+1,
1024-4+1,
512-1,
1024-4-1,
512-strlen("kittycatcat"),
1024-4-strlen("kittycatcat"),
512-strlen("kittycatcat")+1,
1024-4-strlen("kittycatcat")+1,
512-strlen("kittycatcat")-1,
1024-4-strlen("kittycatcat")-1,
strlen("kittycatcat")*(COUNT-2)-1,
};
for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs2_soff_t off = offsets[i];
// read @ offset
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[off % strlen("kittycatcat")],
size) => 0;
// read after
lfs2_file_seek(&lfs2, &file, off+strlen("kittycatcat")+1, LFS2_SEEK_SET)
=> off+strlen("kittycatcat")+1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[(off+1) % strlen("kittycatcat")],
size) => 0;
// read before
lfs2_file_seek(&lfs2, &file, off-strlen("kittycatcat")-1, LFS2_SEEK_SET)
=> off-strlen("kittycatcat")-1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[(off-1) % strlen("kittycatcat")],
size) => 0;
// read @ 0
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
// read @ offset
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[off % strlen("kittycatcat")],
size) => 0;
// read after
lfs2_file_seek(&lfs2, &file, off+strlen("kittycatcat")+1, LFS2_SEEK_SET)
=> off+strlen("kittycatcat")+1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[(off+1) % strlen("kittycatcat")],
size) => 0;
// read before
lfs2_file_seek(&lfs2, &file, off-strlen("kittycatcat")-1, LFS2_SEEK_SET)
=> off-strlen("kittycatcat")-1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[(off-1) % strlen("kittycatcat")],
size) => 0;
// sync
lfs2_file_sync(&lfs2, &file) => 0;
// read @ 0
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
// read @ offset
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[off % strlen("kittycatcat")],
size) => 0;
// read after
lfs2_file_seek(&lfs2, &file, off+strlen("kittycatcat")+1, LFS2_SEEK_SET)
=> off+strlen("kittycatcat")+1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[(off+1) % strlen("kittycatcat")],
size) => 0;
// read before
lfs2_file_seek(&lfs2, &file, off-strlen("kittycatcat")-1, LFS2_SEEK_SET)
=> off-strlen("kittycatcat")-1;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
memcmp(buffer,
&"kittycatcatkittycatcat"[(off-1) % strlen("kittycatcat")],
size) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# boundary seek and writes
[cases.test_seek_boundary_write]
defines.COUNT = 132
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
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;
size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size);
lfs_file_write(&lfs, &file, buffer, size);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
size = strlen("hedgehoghog");
const lfs2_soff_t offsets[] = {
512,
1024-4,
512+1,
1024-4+1,
512-1,
1024-4-1,
512-strlen("kittycatcat"),
1024-4-strlen("kittycatcat"),
512-strlen("kittycatcat")+1,
1024-4-strlen("kittycatcat")+1,
512-strlen("kittycatcat")-1,
1024-4-strlen("kittycatcat")-1,
strlen("kittycatcat")*(COUNT-2)-1,
};
const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019, 1441};
for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs2_soff_t off = offsets[i];
// write @ offset
lfs_soff_t off = offsets[i];
memcpy(buffer, "hedgehoghog", size);
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_write(&lfs2, &file, buffer, size) => size;
// read @ offset
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0;
// read @ 0
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
// read @ offset
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0;
lfs2_file_sync(&lfs2, &file) => 0;
lfs_file_sync(&lfs, &file) => 0;
// read @ 0
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "kittycatcat", size) => 0;
// read @ offset
lfs2_file_seek(&lfs2, &file, off, LFS2_SEEK_SET) => off;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hedgehoghog", size) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# out of bounds seek
@@ -352,123 +205,123 @@ defines = [
{COUNT=4, SKIP=3},
]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
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;
size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) {
lfs2_file_write(&lfs2, &file, buffer, size);
lfs_file_write(&lfs, &file, buffer, size);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
size = strlen("kittycatcat");
lfs2_file_size(&lfs2, &file) => COUNT*size;
lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size,
LFS2_SEEK_SET) => (COUNT+SKIP)*size;
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_size(&lfs, &file) => COUNT*size;
lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size,
LFS_SEEK_SET) => (COUNT+SKIP)*size;
lfs_file_read(&lfs, &file, buffer, size) => 0;
memcpy(buffer, "porcupineee", size);
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs2_file_seek(&lfs2, &file, (COUNT+SKIP)*size,
LFS2_SEEK_SET) => (COUNT+SKIP)*size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size,
LFS_SEEK_SET) => (COUNT+SKIP)*size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "porcupineee", size) => 0;
lfs2_file_seek(&lfs2, &file, COUNT*size,
LFS2_SEEK_SET) => COUNT*size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, COUNT*size,
LFS_SEEK_SET) => COUNT*size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0;
lfs2_file_seek(&lfs2, &file, -((COUNT+SKIP)*size),
LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size;
lfs_file_seek(&lfs, &file, -((COUNT+SKIP)*size),
LFS_SEEK_CUR) => LFS_ERR_INVAL;
lfs_file_tell(&lfs, &file) => (COUNT+1)*size;
lfs2_file_seek(&lfs2, &file, -((COUNT+2*SKIP)*size),
LFS2_SEEK_END) => LFS2_ERR_INVAL;
lfs2_file_tell(&lfs2, &file) => (COUNT+1)*size;
lfs_file_seek(&lfs, &file, -((COUNT+2*SKIP)*size),
LFS_SEEK_END) => LFS_ERR_INVAL;
lfs_file_tell(&lfs, &file) => (COUNT+1)*size;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# inline write and seek
[cases.test_seek_inline_write]
defines.SIZE = [2, 4, 128, 132]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "tinykitty",
LFS2_O_RDWR | LFS2_O_CREAT) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "tinykitty",
LFS_O_RDWR | LFS_O_CREAT) => 0;
int j = 0;
int k = 0;
uint8_t buffer[1024];
memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26);
for (unsigned i = 0; i < SIZE; i++) {
lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1;
lfs2_file_tell(&lfs2, &file) => i+1;
lfs2_file_size(&lfs2, &file) => i+1;
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => i+1;
}
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_tell(&lfs2, &file) => 0;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0;
lfs_file_size(&lfs, &file) => SIZE;
for (unsigned i = 0; i < SIZE; i++) {
uint8_t c;
lfs2_file_read(&lfs2, &file, &c, 1) => 1;
lfs_file_read(&lfs, &file, &c, 1) => 1;
c => buffer[k++ % 26];
}
lfs2_file_sync(&lfs2, &file) => 0;
lfs2_file_tell(&lfs2, &file) => SIZE;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_sync(&lfs, &file) => 0;
lfs_file_tell(&lfs, &file) => SIZE;
lfs_file_size(&lfs, &file) => SIZE;
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
for (unsigned i = 0; i < SIZE; i++) {
lfs2_file_write(&lfs2, &file, &buffer[j++ % 26], 1) => 1;
lfs2_file_tell(&lfs2, &file) => i+1;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs2_file_sync(&lfs2, &file) => 0;
lfs2_file_tell(&lfs2, &file) => i+1;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => SIZE;
lfs_file_sync(&lfs, &file) => 0;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => SIZE;
if (i < SIZE-2) {
uint8_t c[3];
lfs2_file_seek(&lfs2, &file, -1, LFS2_SEEK_CUR) => i;
lfs2_file_read(&lfs2, &file, &c, 3) => 3;
lfs2_file_tell(&lfs2, &file) => i+3;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs2_file_seek(&lfs2, &file, i+1, LFS2_SEEK_SET) => i+1;
lfs2_file_tell(&lfs2, &file) => i+1;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i;
lfs_file_read(&lfs, &file, &c, 3) => 3;
lfs_file_tell(&lfs, &file) => i+3;
lfs_file_size(&lfs, &file) => SIZE;
lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1;
lfs_file_tell(&lfs, &file) => i+1;
lfs_file_size(&lfs, &file) => SIZE;
}
}
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_tell(&lfs2, &file) => 0;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0;
lfs_file_size(&lfs, &file) => SIZE;
for (unsigned i = 0; i < SIZE; i++) {
uint8_t c;
lfs2_file_read(&lfs2, &file, &c, 1) => 1;
lfs_file_read(&lfs, &file, &c, 1) => 1;
c => buffer[k++ % 26];
}
lfs2_file_sync(&lfs2, &file) => 0;
lfs2_file_tell(&lfs2, &file) => SIZE;
lfs2_file_size(&lfs2, &file) => SIZE;
lfs_file_sync(&lfs, &file) => 0;
lfs_file_tell(&lfs, &file) => SIZE;
lfs_file_size(&lfs, &file) => SIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# file seek and write with power-loss
@@ -476,187 +329,75 @@ code = '''
# must be power-of-2 for quadratic probing to be exhaustive
defines.COUNT = [4, 64, 128]
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
lfs2_file_t file;
lfs_file_t file;
uint8_t buffer[1024];
err = lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDONLY);
assert(!err || err == LFS2_ERR_NOENT);
err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT);
if (!err) {
if (lfs2_file_size(&lfs2, &file) != 0) {
lfs2_file_size(&lfs2, &file) => 11*COUNT;
if (lfs_file_size(&lfs, &file) != 0) {
lfs_file_size(&lfs, &file) => 11*COUNT;
for (int j = 0; j < COUNT; j++) {
memset(buffer, 0, 11+1);
lfs2_file_read(&lfs2, &file, buffer, 11) => 11;
lfs_file_read(&lfs, &file, buffer, 11) => 11;
assert(memcmp(buffer, "kittycatcat", 11) == 0 ||
memcmp(buffer, "doggodogdog", 11) == 0);
}
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
if (lfs2_file_size(&lfs2, &file) == 0) {
lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT) => 0;
if (lfs_file_size(&lfs, &file) == 0) {
for (int j = 0; j < COUNT; j++) {
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs_file_write(&lfs, &file, buffer, size) => size;
}
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
strcpy((char*)buffer, "doggodogdog");
size_t size = strlen((char*)buffer);
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => COUNT*size;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => COUNT*size;
// seek and write using quadratic probing to touch all
// 11-byte words in the file
lfs2_off_t off = 0;
lfs_off_t off = 0;
for (int j = 0; j < COUNT; j++) {
off = (5*off + 1) % COUNT;
lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, "kittycatcat", size) == 0 ||
memcmp(buffer, "doggodogdog", size) == 0);
if (memcmp(buffer, "doggodogdog", size) != 0) {
lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
strcpy((char*)buffer, "doggodogdog");
lfs2_file_write(&lfs2, &file, buffer, size) => size;
lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, "doggodogdog", size) == 0);
lfs2_file_sync(&lfs2, &file) => 0;
lfs2_file_seek(&lfs2, &file, off*size, LFS2_SEEK_SET) => off*size;
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0;
lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size;
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, "doggodogdog", size) == 0);
}
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs2_file_open(&lfs2, &file, "kitty", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => COUNT*size;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => COUNT*size;
for (int j = 0; j < COUNT; j++) {
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, "doggodogdog", size) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
'''
# test possible overflow/underflow conditions
#
# note these need -fsanitize=undefined to consistently detect
# overflow/underflow conditions
[cases.test_seek_filemax]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs2_file_write(&lfs2, &file, buffer, size) => size;
// seek with LFS2_SEEK_SET
lfs2_file_seek(&lfs2, &file, LFS2_FILE_MAX, LFS2_SEEK_SET) => LFS2_FILE_MAX;
// seek with LFS2_SEEK_CUR
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_CUR) => LFS2_FILE_MAX;
// the file hasn't changed size, so seek end takes us back to the offset=0
lfs2_file_seek(&lfs2, &file, +10, LFS2_SEEK_END) => size+10;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
'''
[cases.test_seek_underflow]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs2_file_write(&lfs2, &file, buffer, size) => size;
// underflow with LFS2_SEEK_CUR, should error
lfs2_file_seek(&lfs2, &file, -(size+10), LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file, -LFS2_FILE_MAX, LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file, -(size+LFS2_FILE_MAX), LFS2_SEEK_CUR)
=> LFS2_ERR_INVAL;
// underflow with LFS2_SEEK_END, should error
lfs2_file_seek(&lfs2, &file, -(size+10), LFS2_SEEK_END) => LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file, -LFS2_FILE_MAX, LFS2_SEEK_END) => LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file, -(size+LFS2_FILE_MAX), LFS2_SEEK_END)
=> LFS2_ERR_INVAL;
// file pointer should not have changed
lfs2_file_tell(&lfs2, &file) => size;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
'''
[cases.test_seek_overflow]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "kitty",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_APPEND) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "kittycatcat");
size_t size = strlen((char*)buffer);
lfs2_file_write(&lfs2, &file, buffer, size) => size;
// seek to LFS2_FILE_MAX
lfs2_file_seek(&lfs2, &file, LFS2_FILE_MAX, LFS2_SEEK_SET) => LFS2_FILE_MAX;
// overflow with LFS2_SEEK_CUR, should error
lfs2_file_seek(&lfs2, &file, +10, LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file, +LFS2_FILE_MAX, LFS2_SEEK_CUR) => LFS2_ERR_INVAL;
// LFS2_SEEK_SET/END don't care about the current file position, but we can
// still overflow with a large offset
// overflow with LFS2_SEEK_SET, should error
lfs2_file_seek(&lfs2, &file,
+((uint32_t)LFS2_FILE_MAX+10),
LFS2_SEEK_SET) => LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file,
+((uint32_t)LFS2_FILE_MAX+(uint32_t)LFS2_FILE_MAX),
LFS2_SEEK_SET) => LFS2_ERR_INVAL;
// overflow with LFS2_SEEK_END, should error
lfs2_file_seek(&lfs2, &file, +(LFS2_FILE_MAX-size+10), LFS2_SEEK_END)
=> LFS2_ERR_INVAL;
lfs2_file_seek(&lfs2, &file, +(LFS2_FILE_MAX-size+LFS2_FILE_MAX), LFS2_SEEK_END)
=> LFS2_ERR_INVAL;
// file pointer should not have changed
lfs2_file_tell(&lfs2, &file) => LFS2_FILE_MAX;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -1,109 +0,0 @@
# simple shrink
[cases.test_shrink_simple]
defines.BLOCK_COUNT = [10, 15, 20]
defines.AFTER_BLOCK_COUNT = [5, 10, 15, 19]
if = "AFTER_BLOCK_COUNT <= BLOCK_COUNT"
code = '''
#ifdef LFS2_SHRINKNONRELOCATING
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, AFTER_BLOCK_COUNT) => 0;
lfs2_unmount(&lfs2);
if (BLOCK_COUNT != AFTER_BLOCK_COUNT) {
lfs2_mount(&lfs2, cfg) => LFS2_ERR_INVAL;
}
lfs2_t lfs22 = lfs2;
struct lfs2_config cfg2 = *cfg;
cfg2.block_count = AFTER_BLOCK_COUNT;
lfs22.cfg = &cfg2;
lfs2_mount(&lfs22, &cfg2) => 0;
lfs2_unmount(&lfs22) => 0;
#endif
'''
# shrinking full
[cases.test_shrink_full]
defines.BLOCK_COUNT = [10, 15, 20]
defines.AFTER_BLOCK_COUNT = [5, 7, 10, 12, 15, 17, 20]
defines.FILES_COUNT = [7, 8, 9, 10]
if = "AFTER_BLOCK_COUNT <= BLOCK_COUNT && FILES_COUNT + 2 < BLOCK_COUNT"
code = '''
#ifdef LFS2_SHRINKNONRELOCATING
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
// create FILES_COUNT files of BLOCK_SIZE - 50 bytes (to avoid inlining)
lfs2_mount(&lfs2, cfg) => 0;
for (int i = 0; i < FILES_COUNT + 1; i++) {
lfs2_file_t file;
char path[1024];
sprintf(path, "file_%03d", i);
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
char wbuffer[BLOCK_SIZE];
memset(wbuffer, 'b', BLOCK_SIZE);
// Ensure one block is taken per file, but that files are not inlined.
lfs2_size_t size = BLOCK_SIZE - 0x40;
sprintf(wbuffer, "Hi %03d", i);
lfs2_file_write(&lfs2, &file, wbuffer, size) => size;
lfs2_file_close(&lfs2, &file) => 0;
}
int err = lfs2_fs_grow(&lfs2, AFTER_BLOCK_COUNT);
if (err == 0) {
for (int i = 0; i < FILES_COUNT + 1; i++) {
lfs2_file_t file;
char path[1024];
sprintf(path, "file_%03d", i);
lfs2_file_open(&lfs2, &file, path,
LFS2_O_RDONLY ) => 0;
lfs2_size_t size = BLOCK_SIZE - 0x40;
char wbuffer[size];
char wbuffer_ref[size];
// Ensure one block is taken per file, but that files are not inlined.
memset(wbuffer_ref, 'b', size);
sprintf(wbuffer_ref, "Hi %03d", i);
lfs2_file_read(&lfs2, &file, wbuffer, BLOCK_SIZE) => size;
lfs2_file_close(&lfs2, &file) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
wbuffer[j] => wbuffer_ref[j];
}
}
} else {
assert(err == LFS2_ERR_NOTEMPTY);
}
lfs2_unmount(&lfs2) => 0;
if (err == 0 ) {
if ( AFTER_BLOCK_COUNT != BLOCK_COUNT ) {
lfs2_mount(&lfs2, cfg) => LFS2_ERR_INVAL;
}
lfs2_t lfs22 = lfs2;
struct lfs2_config cfg2 = *cfg;
cfg2.block_count = AFTER_BLOCK_COUNT;
lfs22.cfg = &cfg2;
lfs2_mount(&lfs22, &cfg2) => 0;
for (int i = 0; i < FILES_COUNT + 1; i++) {
lfs2_file_t file;
char path[1024];
sprintf(path, "file_%03d", i);
lfs2_file_open(&lfs22, &file, path,
LFS2_O_RDONLY ) => 0;
lfs2_size_t size = BLOCK_SIZE - 0x40;
char wbuffer[size];
char wbuffer_ref[size];
// Ensure one block is taken per file, but that files are not inlined.
memset(wbuffer_ref, 'b', size);
sprintf(wbuffer_ref, "Hi %03d", i);
lfs2_file_read(&lfs22, &file, wbuffer, BLOCK_SIZE) => size;
lfs2_file_close(&lfs22, &file) => 0;
for (lfs2_size_t j = 0; j < size; j++) {
wbuffer[j] => wbuffer_ref[j];
}
}
lfs2_unmount(&lfs22);
}
#endif
'''

View File

@@ -1,93 +1,72 @@
# simple formatting test
[cases.test_superblocks_format]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
'''
# mount/unmount
[cases.test_superblocks_mount]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_unmount(&lfs2) => 0;
'''
# make sure the magic string "littlefs" is always at offset=8
[cases.test_superblocks_magic]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, 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[lfs2_max(16, READ_SIZE)];
cfg->read(cfg, 0, 0, magic, lfs2_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
cfg->read(cfg, 1, 0, magic, lfs2_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_unmount(&lfs) => 0;
'''
# mount/unmount from interpretting a previous superblock block_count
[cases.test_superblocks_mount_unknown_block_count]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
memset(&lfs2, 0, sizeof(lfs2));
struct lfs2_config tweaked_cfg = *cfg;
memset(&lfs, 0, sizeof(lfs));
struct lfs_config tweaked_cfg = *cfg;
tweaked_cfg.block_count = 0;
lfs2_mount(&lfs2, &tweaked_cfg) => 0;
assert(lfs2.block_count == cfg->block_count);
lfs2_unmount(&lfs2) => 0;
lfs_mount(&lfs, &tweaked_cfg) => 0;
assert(lfs.block_count == cfg->block_count);
lfs_unmount(&lfs) => 0;
'''
# reentrant format
[cases.test_superblocks_reentrant_format]
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# invalid mount
[cases.test_superblocks_invalid_mount]
code = '''
lfs2_t lfs2;
lfs2_mount(&lfs2, cfg) => LFS2_ERR_CORRUPT;
lfs_t lfs;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
# test we can read superblock info through lfs2_fs_stat
# test we can read superblock info through lfs_fs_stat
[cases.test_superblocks_stat]
if = 'DISK_VERSION == 0'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// test we can mount and read fsinfo
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
assert(fsinfo.name_max == LFS2_NAME_MAX);
assert(fsinfo.file_max == LFS2_FILE_MAX);
assert(fsinfo.attr_max == LFS2_ATTR_MAX);
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS_DISK_VERSION);
assert(fsinfo.name_max == LFS_NAME_MAX);
assert(fsinfo.file_max == LFS_FILE_MAX);
assert(fsinfo.attr_max == LFS_ATTR_MAX);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
[cases.test_superblocks_stat_tweaked]
@@ -97,25 +76,25 @@ defines.TWEAKED_FILE_MAX = '(1 << 16)-1'
defines.TWEAKED_ATTR_MAX = 512
code = '''
// create filesystem with tweaked params
struct lfs2_config tweaked_cfg = *cfg;
struct lfs_config tweaked_cfg = *cfg;
tweaked_cfg.name_max = TWEAKED_NAME_MAX;
tweaked_cfg.file_max = TWEAKED_FILE_MAX;
tweaked_cfg.attr_max = TWEAKED_ATTR_MAX;
lfs2_t lfs2;
lfs2_format(&lfs2, &tweaked_cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, &tweaked_cfg) => 0;
// test we can mount and read these params with the original config
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS2_DISK_VERSION);
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.disk_version == LFS_DISK_VERSION);
assert(fsinfo.name_max == TWEAKED_NAME_MAX);
assert(fsinfo.file_max == TWEAKED_FILE_MAX);
assert(fsinfo.attr_max == TWEAKED_ATTR_MAX);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# expanding superblock
@@ -123,66 +102,33 @@ code = '''
defines.BLOCK_CYCLES = [32, 33, 1]
defines.N = [10, 100, 1000]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "dummy",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_file_close(&lfs2, &file) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "dummy", &info) => 0;
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 == LFS2_TYPE_REG);
lfs2_remove(&lfs2, "dummy") => 0;
assert(info.type == LFS_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// one last check after power-cycle
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "dummy",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_file_close(&lfs2, &file) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "dummy", &info) => 0;
lfs_mount(&lfs, cfg) => 0;
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 == LFS2_TYPE_REG);
lfs2_unmount(&lfs2) => 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 = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "dummy",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_file_close(&lfs2, &file) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
lfs2_remove(&lfs2, "dummy") => 0;
}
lfs2_unmount(&lfs2) => 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[lfs2_max(16, READ_SIZE)];
cfg->read(cfg, 0, 0, magic, lfs2_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
cfg->read(cfg, 1, 0, magic, lfs2_max(16, READ_SIZE)) => 0;
assert(memcmp(&magic[8], "littlefs", 8) == 0);
assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0;
'''
# expanding superblock with power cycle
@@ -190,37 +136,37 @@ code = '''
defines.BLOCK_CYCLES = [32, 33, 1]
defines.N = [10, 100, 1000]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// remove lingering dummy?
struct lfs2_info info;
int err = lfs2_stat(&lfs2, "dummy", &info);
assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0));
struct lfs_info info;
int err = lfs_stat(&lfs, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
if (!err) {
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
lfs2_remove(&lfs2, "dummy") => 0;
assert(info.type == LFS_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0;
}
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "dummy",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_stat(&lfs2, "dummy", &info) => 0;
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;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
lfs2_unmount(&lfs2) => 0;
assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0;
}
// one last check after power-cycle
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "dummy", &info) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
lfs2_unmount(&lfs2) => 0;
assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0;
'''
# reentrant expanding superblock
@@ -228,195 +174,190 @@ code = '''
defines.BLOCK_CYCLES = [2, 1]
defines.N = 24
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
for (int i = 0; i < N; i++) {
// remove lingering dummy?
struct lfs2_info info;
err = lfs2_stat(&lfs2, "dummy", &info);
assert(err == 0 || (err == LFS2_ERR_NOENT && i == 0));
struct lfs_info info;
err = lfs_stat(&lfs, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
if (!err) {
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
lfs2_remove(&lfs2, "dummy") => 0;
assert(info.type == LFS_TYPE_REG);
lfs_remove(&lfs, "dummy") => 0;
}
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "dummy",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_stat(&lfs2, "dummy", &info) => 0;
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;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
assert(info.type == LFS_TYPE_REG);
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// one last check after power-cycle
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, "dummy", &info) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS2_TYPE_REG);
lfs2_unmount(&lfs2) => 0;
assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0;
'''
# mount with unknown block_count
[cases.test_superblocks_unknown_blocks]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// known block_size/block_count
cfg->block_size = BLOCK_SIZE;
cfg->block_count = BLOCK_COUNT;
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// unknown block_count
cfg->block_size = BLOCK_SIZE;
cfg->block_count = 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// do some work
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "test",
LFS2_O_CREAT | LFS2_O_EXCL | LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file, "hello!", 6) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "test",
LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hello!", 6) => 6;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
uint8_t buffer[256];
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
lfs_file_close(&lfs, &file) => 0;
assert(memcmp(buffer, "hello!", 6) == 0);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# mount with blocks fewer than the erase_count
[cases.test_superblocks_fewer_blocks]
defines.BLOCK_COUNT = ['ERASE_COUNT/2', 'ERASE_COUNT/4', '2']
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// known block_size/block_count
cfg->block_size = BLOCK_SIZE;
cfg->block_count = BLOCK_COUNT;
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// incorrect block_count
cfg->block_size = BLOCK_SIZE;
cfg->block_count = ERASE_COUNT;
lfs2_mount(&lfs2, cfg) => LFS2_ERR_INVAL;
lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
// unknown block_count
cfg->block_size = BLOCK_SIZE;
cfg->block_count = 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// do some work
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "test",
LFS2_O_CREAT | LFS2_O_EXCL | LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file, "hello!", 6) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "test",
LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hello!", 6) => 6;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
uint8_t buffer[256];
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
lfs_file_close(&lfs, &file) => 0;
assert(memcmp(buffer, "hello!", 6) == 0);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# mount with more blocks than the erase_count
[cases.test_superblocks_more_blocks]
defines.FORMAT_BLOCK_COUNT = '2*ERASE_COUNT'
in = 'lfs2.c'
in = 'lfs.c'
code = '''
lfs2_t lfs2;
lfs2_init(&lfs2, cfg) => 0;
lfs2.block_count = BLOCK_COUNT;
lfs_t lfs;
lfs_init(&lfs, cfg) => 0;
lfs.block_count = BLOCK_COUNT;
lfs2_mdir_t root = {
lfs_mdir_t root = {
.pair = {0, 0}, // make sure this goes into block 0
.rev = 0,
.off = sizeof(uint32_t),
.etag = 0xffffffff,
.count = 0,
.tail = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL},
.tail = {LFS_BLOCK_NULL, LFS_BLOCK_NULL},
.erased = false,
.split = false,
};
lfs2_superblock_t superblock = {
.version = LFS2_DISK_VERSION,
lfs_superblock_t superblock = {
.version = LFS_DISK_VERSION,
.block_size = BLOCK_SIZE,
.block_count = FORMAT_BLOCK_COUNT,
.name_max = LFS2_NAME_MAX,
.file_max = LFS2_FILE_MAX,
.attr_max = LFS2_ATTR_MAX,
.name_max = LFS_NAME_MAX,
.file_max = LFS_FILE_MAX,
.attr_max = LFS_ATTR_MAX,
};
lfs2_superblock_tole32(&superblock);
lfs2_dir_commit(&lfs2, &root, LFS2_MKATTRS(
{LFS2_MKTAG(LFS2_TYPE_CREATE, 0, 0), NULL},
{LFS2_MKTAG(LFS2_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
{LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
lfs_superblock_tole32(&superblock);
lfs_dir_commit(&lfs, &root, LFS_MKATTRS(
{LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL},
{LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
{LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
&superblock})) => 0;
lfs2_deinit(&lfs2) => 0;
lfs_deinit(&lfs) => 0;
// known block_size/block_count
cfg->block_size = BLOCK_SIZE;
cfg->block_count = BLOCK_COUNT;
lfs2_mount(&lfs2, cfg) => LFS2_ERR_INVAL;
lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
'''
# mount and grow the filesystem
@@ -425,8 +366,8 @@ defines.BLOCK_COUNT = ['ERASE_COUNT/2', 'ERASE_COUNT/4', '2']
defines.BLOCK_COUNT_2 = 'ERASE_COUNT'
defines.KNOWN_BLOCK_COUNT = [true, false]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
if (KNOWN_BLOCK_COUNT) {
cfg->block_count = BLOCK_COUNT;
@@ -435,34 +376,34 @@ code = '''
}
// mount with block_size < erase_size
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_fsinfo fsinfo;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// same size is a noop
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, BLOCK_COUNT) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_grow(&lfs, BLOCK_COUNT) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// grow to new size
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, BLOCK_COUNT_2) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
if (KNOWN_BLOCK_COUNT) {
cfg->block_count = BLOCK_COUNT_2;
@@ -470,15 +411,15 @@ code = '''
cfg->block_count = 0;
}
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// mounting with the previous size should fail
cfg->block_count = BLOCK_COUNT;
lfs2_mount(&lfs2, cfg) => LFS2_ERR_INVAL;
lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
if (KNOWN_BLOCK_COUNT) {
cfg->block_count = BLOCK_COUNT_2;
@@ -487,174 +428,39 @@ code = '''
}
// same size is a noop
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, BLOCK_COUNT_2) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_grow(&lfs, BLOCK_COUNT_2) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
// do some work
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "test",
LFS2_O_CREAT | LFS2_O_EXCL | LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file, "hello!", 6) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "test",
LFS_O_CREAT | LFS_O_EXCL | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hello!", 6) => 6;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_fs_stat(&lfs, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0;
lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
uint8_t buffer[256];
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => 6;
lfs_file_close(&lfs, &file) => 0;
assert(memcmp(buffer, "hello!", 6) == 0);
lfs2_unmount(&lfs2) => 0;
'''
# mount and grow the filesystem
[cases.test_superblocks_shrink]
defines.BLOCK_COUNT = 'ERASE_COUNT'
defines.BLOCK_COUNT_2 = ['ERASE_COUNT/2', 'ERASE_COUNT/4', '2']
defines.KNOWN_BLOCK_COUNT = [true, false]
code = '''
#ifdef LFS2_SHRINKNONRELOCATING
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
if (KNOWN_BLOCK_COUNT) {
cfg->block_count = BLOCK_COUNT;
} else {
cfg->block_count = 0;
}
// mount with block_size < erase_size
lfs2_mount(&lfs2, cfg) => 0;
struct lfs2_fsinfo fsinfo;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
// same size is a noop
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, BLOCK_COUNT) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT);
lfs2_unmount(&lfs2) => 0;
// grow to new size
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, BLOCK_COUNT_2) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
if (KNOWN_BLOCK_COUNT) {
cfg->block_count = BLOCK_COUNT_2;
} else {
cfg->block_count = 0;
}
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
// mounting with the previous size should fail
cfg->block_count = BLOCK_COUNT;
lfs2_mount(&lfs2, cfg) => LFS2_ERR_INVAL;
if (KNOWN_BLOCK_COUNT) {
cfg->block_count = BLOCK_COUNT_2;
} else {
cfg->block_count = 0;
}
// same size is a noop
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_grow(&lfs2, BLOCK_COUNT_2) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_unmount(&lfs2) => 0;
// do some work
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "test",
LFS2_O_CREAT | LFS2_O_EXCL | LFS2_O_WRONLY) => 0;
lfs2_file_write(&lfs2, &file, "hello!", 6) => 6;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_fs_stat(&lfs2, &fsinfo) => 0;
assert(fsinfo.block_size == BLOCK_SIZE);
assert(fsinfo.block_count == BLOCK_COUNT_2);
lfs2_file_open(&lfs2, &file, "test", LFS2_O_RDONLY) => 0;
uint8_t buffer[256];
lfs2_file_read(&lfs2, &file, buffer, sizeof(buffer)) => 6;
lfs2_file_close(&lfs2, &file) => 0;
assert(memcmp(buffer, "hello!", 6) == 0);
lfs2_unmount(&lfs2) => 0;
#endif
'''
# test that metadata_max does not cause problems for superblock compaction
[cases.test_superblocks_metadata_max]
defines.METADATA_MAX = [
'lfs2_max(512, PROG_SIZE)',
'lfs2_max(BLOCK_SIZE/2, PROG_SIZE)',
'BLOCK_SIZE'
]
defines.N = [10, 100, 1000]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
for (int i = 0; i < N; i++) {
lfs2_file_t file;
char name[256];
sprintf(name, "hello%03x", i);
lfs2_file_open(&lfs2, &file, name,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_EXCL) => 0;
lfs2_file_close(&lfs2, &file) => 0;
struct lfs2_info info;
lfs2_stat(&lfs2, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS2_TYPE_REG);
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''

View File

@@ -4,49 +4,49 @@ defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
if = 'MEDIUMSIZE < LARGESIZE'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "baldynoop",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, LARGESIZE-j))
=> lfs2_min(size, LARGESIZE-j);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
}
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_size(&lfs, &file) => LARGESIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE;
lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
size = strlen("hair");
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs2_min(size, MEDIUMSIZE-j)) => 0;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# truncate and read
@@ -55,113 +55,113 @@ defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
if = 'MEDIUMSIZE < LARGESIZE'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "baldyread",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldyread",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, LARGESIZE-j))
=> lfs2_min(size, LARGESIZE-j);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
}
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_size(&lfs, &file) => LARGESIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE;
lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
size = strlen("hair");
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs2_min(size, MEDIUMSIZE-j)) => 0;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldyread", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
size = strlen("hair");
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs2_min(size, MEDIUMSIZE-j)) => 0;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# write, truncate, and read
[cases.test_truncate_write_read]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "sequence",
LFS2_O_RDWR | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "sequence",
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t buffer[1024];
size_t size = lfs2_min(lfs2.cfg->cache_size, sizeof(buffer)/2);
lfs2_size_t qsize = size / 4;
size_t size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2);
lfs_size_t qsize = size / 4;
uint8_t *wb = buffer;
uint8_t *rb = buffer + size;
for (lfs2_off_t j = 0; j < size; ++j) {
for (lfs_off_t j = 0; j < size; ++j) {
wb[j] = j;
}
/* Spread sequence over size */
lfs2_file_write(&lfs2, &file, wb, size) => size;
lfs2_file_size(&lfs2, &file) => size;
lfs2_file_tell(&lfs2, &file) => size;
lfs_file_write(&lfs, &file, wb, size) => size;
lfs_file_size(&lfs, &file) => size;
lfs_file_tell(&lfs, &file) => size;
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs2_file_tell(&lfs2, &file) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfs_file_tell(&lfs, &file) => 0;
/* Chop off the last quarter */
lfs2_size_t trunc = size - qsize;
lfs2_file_truncate(&lfs2, &file, trunc) => 0;
lfs2_file_tell(&lfs2, &file) => 0;
lfs2_file_size(&lfs2, &file) => trunc;
lfs_size_t trunc = size - qsize;
lfs_file_truncate(&lfs, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => 0;
lfs_file_size(&lfs, &file) => trunc;
/* Read should produce first 3/4 */
lfs2_file_read(&lfs2, &file, rb, size) => trunc;
lfs_file_read(&lfs, &file, rb, size) => trunc;
memcmp(rb, wb, trunc) => 0;
/* Move to 1/4 */
lfs2_file_size(&lfs2, &file) => trunc;
lfs2_file_seek(&lfs2, &file, qsize, LFS2_SEEK_SET) => qsize;
lfs2_file_tell(&lfs2, &file) => qsize;
lfs_file_size(&lfs, &file) => trunc;
lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize;
lfs_file_tell(&lfs, &file) => qsize;
/* Chop to 1/2 */
trunc -= qsize;
lfs2_file_truncate(&lfs2, &file, trunc) => 0;
lfs2_file_tell(&lfs2, &file) => qsize;
lfs2_file_size(&lfs2, &file) => trunc;
lfs_file_truncate(&lfs, &file, trunc) => 0;
lfs_file_tell(&lfs, &file) => qsize;
lfs_file_size(&lfs, &file) => trunc;
/* Read should produce second quarter */
lfs2_file_read(&lfs2, &file, rb, size) => trunc - qsize;
lfs_file_read(&lfs, &file, rb, size) => trunc - qsize;
memcmp(rb, wb + qsize, trunc - qsize) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# truncate and write
@@ -170,59 +170,59 @@ defines.MEDIUMSIZE = [31, 32, 33, 511, 512, 513, 2047, 2048, 2049]
defines.LARGESIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
if = 'MEDIUMSIZE < LARGESIZE'
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "baldywrite",
LFS2_O_WRONLY | LFS2_O_CREAT) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldywrite",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, LARGESIZE-j))
=> lfs2_min(size, LARGESIZE-j);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
}
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_size(&lfs, &file) => LARGESIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE;
/* truncate */
lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
/* and write */
strcpy((char*)buffer, "bald");
size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
}
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldywrite", LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
size = strlen("bald");
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
memcmp(buffer, "bald", lfs2_min(size, MEDIUMSIZE-j)) => 0;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "bald", lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''
# truncate write under powerloss
@@ -231,79 +231,75 @@ defines.SMALLSIZE = [4, 512]
defines.MEDIUMSIZE = [0, 3, 4, 5, 31, 32, 33, 511, 512, 513, 1023, 1024, 1025]
defines.LARGESIZE = 2048
reentrant = true
defines.POWERLOSS_BEHAVIOR = [
'LFS2_EMUBD_POWERLOSS_NOOP',
'LFS2_EMUBD_POWERLOSS_OOO',
]
code = '''
lfs2_t lfs2;
int err = lfs2_mount(&lfs2, cfg);
lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) {
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
}
lfs2_file_t file;
err = lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDONLY);
assert(!err || err == LFS2_ERR_NOENT);
lfs_file_t file;
err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT);
if (!err) {
size_t size = lfs2_file_size(&lfs2, &file);
size_t size = lfs_file_size(&lfs, &file);
assert(size == 0 ||
size == (size_t)LARGESIZE ||
size == (size_t)MEDIUMSIZE ||
size == (size_t)SMALLSIZE);
for (lfs2_off_t j = 0; j < size; j += 4) {
for (lfs_off_t j = 0; j < size; j += 4) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(4, size-j))
=> lfs2_min(4, size-j);
assert(memcmp(buffer, "hair", lfs2_min(4, size-j)) == 0 ||
memcmp(buffer, "bald", lfs2_min(4, size-j)) == 0 ||
memcmp(buffer, "comb", lfs2_min(4, size-j)) == 0);
lfs_file_read(&lfs, &file, buffer, lfs_min(4, size-j))
=> lfs_min(4, size-j);
assert(memcmp(buffer, "hair", lfs_min(4, size-j)) == 0 ||
memcmp(buffer, "bald", lfs_min(4, size-j)) == 0 ||
memcmp(buffer, "comb", lfs_min(4, size-j)) == 0);
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_file_open(&lfs2, &file, "baldy",
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs2_file_size(&lfs2, &file) => 0;
lfs_file_open(&lfs, &file, "baldy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
lfs_file_size(&lfs, &file) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < LARGESIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, LARGESIZE-j))
=> lfs2_min(size, LARGESIZE-j);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, LARGESIZE-j))
=> lfs_min(size, LARGESIZE-j);
}
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE;
lfs_file_close(&lfs, &file) => 0;
lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => LARGESIZE;
lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE;
/* truncate */
lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
/* and write */
strcpy((char*)buffer, "bald");
size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
}
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs_file_close(&lfs, &file) => 0;
lfs2_file_open(&lfs2, &file, "baldy", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs2_file_truncate(&lfs2, &file, SMALLSIZE) => 0;
lfs2_file_size(&lfs2, &file) => SMALLSIZE;
lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, SMALLSIZE) => 0;
lfs_file_size(&lfs, &file) => SMALLSIZE;
strcpy((char*)buffer, "comb");
size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < SMALLSIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, SMALLSIZE-j))
=> lfs2_min(size, SMALLSIZE-j);
for (lfs_off_t j = 0; j < SMALLSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, SMALLSIZE-j))
=> lfs_min(size, SMALLSIZE-j);
}
lfs2_file_size(&lfs2, &file) => SMALLSIZE;
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_size(&lfs, &file) => SMALLSIZE;
lfs_file_close(&lfs, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# more aggressive general truncation tests
@@ -313,13 +309,13 @@ defines.SMALLSIZE = 32
defines.MEDIUMSIZE = 2048
defines.LARGESIZE = 8192
code = '''
lfs2_t lfs2;
lfs_t lfs;
#define COUNT 5
const struct {
lfs2_off_t startsizes[COUNT];
lfs2_off_t startseeks[COUNT];
lfs2_off_t hotsizes[COUNT];
lfs2_off_t coldsizes[COUNT];
lfs_off_t startsizes[COUNT];
lfs_off_t startseeks[COUNT];
lfs_off_t hotsizes[COUNT];
lfs_off_t coldsizes[COUNT];
} configs[] = {
// cold shrinking
{{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE},
@@ -353,151 +349,151 @@ code = '''
{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}},
};
const lfs2_off_t *startsizes = configs[CONFIG].startsizes;
const lfs2_off_t *startseeks = configs[CONFIG].startseeks;
const lfs2_off_t *hotsizes = configs[CONFIG].hotsizes;
const lfs2_off_t *coldsizes = configs[CONFIG].coldsizes;
const lfs_off_t *startsizes = configs[CONFIG].startsizes;
const lfs_off_t *startseeks = configs[CONFIG].startseeks;
const lfs_off_t *hotsizes = configs[CONFIG].hotsizes;
const lfs_off_t *coldsizes = configs[CONFIG].coldsizes;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hairyhead%d", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path,
LFS2_O_WRONLY | LFS2_O_CREAT | LFS2_O_TRUNC) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < startsizes[i]; j += size) {
lfs2_file_write(&lfs2, &file, buffer, size) => size;
for (lfs_off_t j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
lfs2_file_size(&lfs2, &file) => startsizes[i];
lfs_file_size(&lfs, &file) => startsizes[i];
if (startseeks[i] != startsizes[i]) {
lfs2_file_seek(&lfs2, &file,
startseeks[i], LFS2_SEEK_SET) => startseeks[i];
lfs_file_seek(&lfs, &file,
startseeks[i], LFS_SEEK_SET) => startseeks[i];
}
lfs2_file_truncate(&lfs2, &file, hotsizes[i]) => 0;
lfs2_file_size(&lfs2, &file) => hotsizes[i];
lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i];
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hairyhead%d", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => hotsizes[i];
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i];
size_t size = strlen("hair");
lfs2_off_t j = 0;
lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
for (; j < hotsizes[i]; j += size) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0;
}
lfs2_file_truncate(&lfs2, &file, coldsizes[i]) => 0;
lfs2_file_size(&lfs2, &file) => coldsizes[i];
lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i];
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hairyhead%d", i);
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, path, LFS2_O_RDONLY) => 0;
lfs2_file_size(&lfs2, &file) => coldsizes[i];
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i];
size_t size = strlen("hair");
lfs2_off_t j = 0;
lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
for (; j < coldsizes[i]; j += size) {
uint8_t buffer[1024];
lfs2_file_read(&lfs2, &file, buffer, size) => size;
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0;
}
lfs2_file_close(&lfs2, &file) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs2_unmount(&lfs2) => 0;
lfs_unmount(&lfs) => 0;
'''
# noop truncate
[cases.test_truncate_nop]
defines.MEDIUMSIZE = [32, 33, 512, 513, 2048, 2049, 8192, 8193]
code = '''
lfs2_t lfs2;
lfs2_format(&lfs2, cfg) => 0;
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_t file;
lfs2_file_open(&lfs2, &file, "baldynoop",
LFS2_O_RDWR | LFS2_O_CREAT) => 0;
lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_RDWR | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
size_t size = strlen((char*)buffer);
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_write(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
// this truncate should do nothing
lfs2_file_truncate(&lfs2, &file, j+lfs2_min(size, MEDIUMSIZE-j)) => 0;
lfs_file_truncate(&lfs, &file, j+lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
lfs2_file_seek(&lfs2, &file, 0, LFS2_SEEK_SET) => 0;
lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
// should do nothing again
lfs2_file_truncate(&lfs2, &file, MEDIUMSIZE) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs2_min(size, MEDIUMSIZE-j)) => 0;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// still there after reboot?
lfs2_mount(&lfs2, cfg) => 0;
lfs2_file_open(&lfs2, &file, "baldynoop", LFS2_O_RDWR) => 0;
lfs2_file_size(&lfs2, &file) => MEDIUMSIZE;
for (lfs2_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs2_file_read(&lfs2, &file, buffer, lfs2_min(size, MEDIUMSIZE-j))
=> lfs2_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs2_min(size, MEDIUMSIZE-j)) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_read(&lfs, &file, buffer, lfs_min(size, MEDIUMSIZE-j))
=> lfs_min(size, MEDIUMSIZE-j);
memcmp(buffer, "hair", lfs_min(size, MEDIUMSIZE-j)) => 0;
}
lfs2_file_read(&lfs2, &file, buffer, size) => 0;
lfs2_file_close(&lfs2, &file) => 0;
lfs2_unmount(&lfs2) => 0;
lfs_file_read(&lfs, &file, buffer, size) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
'''