test code v1
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# Test Execution Checklist
|
||||
|
||||
## Acceptance Rules
|
||||
|
||||
- [x] Execute each TC from its Markdown procedure and record direct command
|
||||
status, fixture/module hashes, kernel behavior, and cleanup state.
|
||||
- [x] Treat fixture generation and static review as supporting evidence only.
|
||||
- [x] Do not use retired wrappers, result collectors, or unconditional PASS
|
||||
output as acceptance evidence.
|
||||
- [x] Keep CI and automated kernel-test infrastructure outside this task.
|
||||
|
||||
## Specification Audit
|
||||
|
||||
- [x] TC000 is present as the non-executable template.
|
||||
- [x] TC001-TC161 are present exactly once.
|
||||
- [x] Bounded filename audit: 162 rows, 162 unique IDs, no duplicate or gap.
|
||||
- [x] G1-G8 table audit: 156 rows, 156 unique IDs, no duplicate or omission.
|
||||
- [x] TC157-TC161 add five unique final-review cases.
|
||||
|
||||
## Canonical Execution Groups
|
||||
|
||||
| Group | Scope | Final result | Evidence |
|
||||
| --- | --- | --- | --- |
|
||||
| G1 | TC001, TC007, TC009, TC011-TC014, TC019-TC040, TC147, TC150, TC151 | 32 PASS | `results/manual/2026-08-09T0710Z-g1/` |
|
||||
| G2 | TC002, TC008, TC010, TC015-TC018, TC112-TC116, TC119 | 13 PASS | `results/manual/2026-08-09T0710Z-g2/` |
|
||||
| G3 | TC041-TC066, TC141, TC148, TC149, TC152, TC153 | 31 PASS | `results/manual/2026-08-09T1059Z-g3/` plus TC060 fixed-source rerun |
|
||||
| G4 | TC005, TC067-TC083, TC117, TC134-TC140, TC142 | 27 PASS | `results/manual/2026-08-09T0839Z-g4/` |
|
||||
| G5 | TC003, TC004, TC084-TC092, TC102-TC110, TC143-TC146 | 23 PASS, 1 PARTIAL | `results/manual/2026-08-09T1236Z-g5/` |
|
||||
| G6 | TC006, TC093-TC101, TC118 | 11 PASS | `results/manual/2026-08-09T1244Z-g6/` |
|
||||
| G7 | TC120-TC130 | 11 PASS | `results/manual/2026-08-09T1359Z-g7/` |
|
||||
| G8 | TC111, TC131-TC133, TC154-TC156 | 7 PASS | `results/manual/2026-08-09T1343Z-g8/` |
|
||||
| Final | TC157-TC161 | 5 PASS | `results/manual/2026-08-09T1804Z-final-review-independent/` |
|
||||
|
||||
## Final Review Cases
|
||||
|
||||
- [x] TC157: global 16/32-byte explicit-extent order validation.
|
||||
- [x] TC158: extended compressed inode 48-bit block-count accounting.
|
||||
- [x] TC159: special-vnode combined setattr rejection.
|
||||
- [x] TC160: dot-omitted `OFF_MAX` cookie rejection.
|
||||
- [x] TC161: fatal `nm` failure and uncontaminated post-shim rebuild.
|
||||
|
||||
## Build and Runtime Sign-Off
|
||||
|
||||
- [x] Exact final source baseline:
|
||||
`fcc85b93d5f8fd9671686bd68bf3b086c8bd25cf`.
|
||||
- [x] `WITH_ZSTDIO=0` built with kernel `-Werror`; KLD SHA256
|
||||
`15fda9d334132cd81769ce4dff4f8411a6e2b4cf7531c352530d0de85f42a2d2`.
|
||||
- [x] `WITH_ZSTDIO=1` built with kernel `-Werror`; KLD SHA256
|
||||
`23782dc0ce7da188807d35020bf2d8c6044b796c5c9a8746b398ba784cd6ad4e`.
|
||||
- [x] Both final KLDs loaded and completed a read-only mount smoke.
|
||||
- [x] Final guest EROFS mounts, md units, EROFS KLDs, and DTrace KLDs: zero.
|
||||
- [x] repo22 generated build/object/image/bytecode artifacts removed.
|
||||
|
||||
## Final Statistics
|
||||
|
||||
```text
|
||||
Executable test cases: 161
|
||||
Executed: 161
|
||||
PASS: 160
|
||||
PARTIAL: 1 (TC146)
|
||||
FAIL: 0
|
||||
KERNEL-FAIL: 0
|
||||
ENVIRONMENT-UNAVAILABLE: 0
|
||||
SHELVED test case: 0
|
||||
```
|
||||
|
||||
TC146 is PARTIAL because a positive explicit mapped-payload fixture is not
|
||||
available. Its shelved subitem is not a separate TC. TC010, TC060, and TC153
|
||||
are resolved historical issues.
|
||||
|
||||
## Residual Work
|
||||
|
||||
- [ ] Obtain an independently validated positive explicit mapped-payload
|
||||
fixture and complete the remaining TC146 subfeature.
|
||||
- [ ] Optionally extend TC157 with first-nonzero-`lstart` and extreme
|
||||
extent-count performance coverage if the format contract and a qualified
|
||||
fixture require it.
|
||||
- [ ] CI remains intentionally unimplemented and outside this test effort.
|
||||
@@ -0,0 +1,69 @@
|
||||
# G1 Manual Test Setup
|
||||
|
||||
This setup supports only the G1 test set. It prepares fixtures and probes; it
|
||||
does not execute tests, assign results, or append PASS output.
|
||||
|
||||
## Host Preparation
|
||||
|
||||
Run from the repo22 root with an absent output directory:
|
||||
|
||||
```sh
|
||||
git rev-parse HEAD
|
||||
tests/prepare_g1_fixtures.sh /work/build/repo22-g1
|
||||
(cd /work/build/repo22-g1/images && sha256sum -c IMAGE-SHA256SUMS)
|
||||
(cd /work/build/repo22-g1 && sha256sum -c SOURCE-SHA256SUMS)
|
||||
(cd /work/build/repo22-g1 && sha256sum -c SOURCE-METADATA.sha256)
|
||||
```
|
||||
|
||||
Record `fixture-evidence.txt`, all three checksum manifests, the erofs-utils
|
||||
version, and the KLD SHA256. Production erofs-utils 1.8.6 does not recognize
|
||||
the 48-bit incompat bit, so `root8-48bit.erofs`,
|
||||
`fallback-48bit-root2.erofs`, and `compact-dot-omitted.erofs` are qualified by
|
||||
the structured transformer's field/CRC assertions plus the required FreeBSD
|
||||
mount, not by a false `fsck.erofs` PASS.
|
||||
|
||||
Transfer `images/`, `source/`, `expected/`, the checksum/evidence files, the
|
||||
exact KLD, and the C probes used by a TC to an empty guest directory. Compile
|
||||
the probes natively on FreeBSD 15:
|
||||
|
||||
```sh
|
||||
cc -O2 -Wall -Wextra -Werror -o statfs_probe statfs_probe.c
|
||||
cc -O2 -Wall -Wextra -Werror -o stat_special stat_special.c
|
||||
cc -O2 -Wall -Wextra -Werror -o read_probe read_probe.c
|
||||
cc -O2 -Wall -Wextra -Werror -o mmap_fault mmap_fault.c
|
||||
cc -O2 -Wall -Wextra -Werror -o nfs_fh_tool nfs_fh_tool.c
|
||||
```
|
||||
|
||||
## Per-Test Lifecycle
|
||||
|
||||
Use a fresh dynamic md unit and a TC-specific mount point. Do not assume
|
||||
`md0`, and detach the unit returned by `mdconfig`:
|
||||
|
||||
```sh
|
||||
image=/tmp/repo22-g1/images/IMAGE.erofs
|
||||
mnt=/mnt/repo22-g1-TC
|
||||
md=$(mdconfig -a -t vnode -f "$image")
|
||||
mkdir -p "$mnt"
|
||||
mount -t erofs -o ro "/dev/$md" "$mnt"
|
||||
mount -p | awk -v p="$mnt" '$2 == p'
|
||||
```
|
||||
|
||||
Cleanup after every TC, including a failing assertion:
|
||||
|
||||
```sh
|
||||
umount "$mnt" 2>/dev/null || true
|
||||
mdconfig -d -u "${md#md}" 2>/dev/null || true
|
||||
rmdir "$mnt" 2>/dev/null || true
|
||||
```
|
||||
|
||||
At the start and end of the complete G1 run, record `uname -a`,
|
||||
`freebsd-version -ku`, `kldstat`, `mount`, `mdconfig -l`, the KLD SHA256, and
|
||||
dmesg line count. The final state must contain no EROFS mount, EROFS KLD, or G1
|
||||
md provider.
|
||||
|
||||
## Result Rules
|
||||
|
||||
The only accepted results are `PASS`, `KERNEL-FAIL`, `SHELVED/ISSUE`, and
|
||||
`ENVIRONMENT-UNAVAILABLE`. Host inspection alone cannot produce PASS. A
|
||||
kernel behavior failure must retain the observed errno/output and be recorded
|
||||
in `issues/`; it must not be relabeled PASS.
|
||||
@@ -0,0 +1,58 @@
|
||||
# G3 Manual Test Setup
|
||||
|
||||
This setup supports only TC041-TC066, TC141, TC148, TC149, TC152, and
|
||||
TC153. It prepares fixtures and native probes; it does not run tests or assign
|
||||
results.
|
||||
|
||||
## Host Preparation
|
||||
|
||||
From the repo22 root, use an absent output directory:
|
||||
|
||||
git rev-parse HEAD
|
||||
tests/prepare_g3_fixtures.sh /work/build/repo22-g3
|
||||
(cd /work/build/repo22-g3/vfs && sha256sum -c IMAGE-SHA256SUMS)
|
||||
(cd /work/build/repo22-g3/vfs/source &&
|
||||
sha256sum -c ../SOURCE-SHA256SUMS)
|
||||
(cd /work/build/repo22-g3/metadata && sha256sum -c SHA256SUMS)
|
||||
(cd /work/build/repo22-g3/final && sha256sum -c SHA256SUMS)
|
||||
|
||||
Record fixture-evidence.txt, all checksum manifests, the erofs-utils version,
|
||||
the exact source commit, and the KLD SHA256. Transfer the fixtures, sources,
|
||||
and only these native probes to the FreeBSD 15 guest:
|
||||
|
||||
readdir_probe.c g3_vfs_probe.c stat_special.c nfs_fh_tool.c
|
||||
mmap_fault.c sparse_hole_probe.c
|
||||
|
||||
## Guest Preparation
|
||||
|
||||
Build the KLD natively from an archive exported from the recorded commit.
|
||||
Build probes directly; no runner or result wrapper is permitted:
|
||||
|
||||
cc -O2 -Wall -Wextra -Werror -std=c17 readdir_probe.c -o readdir_probe
|
||||
cc -O2 -Wall -Wextra -Werror -std=c17 g3_vfs_probe.c -o g3_vfs_probe
|
||||
cc -O2 -Wall -Wextra -Werror -std=c17 stat_special.c -o stat_special
|
||||
cc -O2 -Wall -Wextra -Werror -std=c17 nfs_fh_tool.c -o nfs_fh_tool
|
||||
cc -O2 -Wall -Wextra -Werror -std=c17 mmap_fault.c -o mmap_fault
|
||||
cc -O2 -Wall -Wextra -Werror -std=c17 sparse_hole_probe.c \
|
||||
-o sparse_hole_probe
|
||||
|
||||
Before the first test, require no EROFS mount, no md provider, and no stale
|
||||
EROFS KLD. Load only the exact KLD under test. For each test, attach a fresh
|
||||
dynamic vnode md, mount read-only, execute that numbered Markdown procedure,
|
||||
then unmount and detach before continuing.
|
||||
|
||||
The report records the literal command, exit status or syscall errno, relevant
|
||||
fixture/data/KLD hashes, dmesg delta, and cleanup state for every test.
|
||||
|
||||
## Common Mount Pattern
|
||||
|
||||
mkdir -p /tmp/repo22-g3/mnt
|
||||
unit=$(mdconfig -a -t vnode -f IMAGE)
|
||||
mount -t erofs -o ro "/dev/$unit" /tmp/repo22-g3/mnt
|
||||
# Execute exactly one numbered test.
|
||||
umount /tmp/repo22-g3/mnt
|
||||
mdconfig -d -u "$unit"
|
||||
|
||||
TC153 additionally creates and removes its documented multi-terabyte sparse
|
||||
provider. Final cleanup requires zero EROFS mounts, zero md providers, the test
|
||||
KLD unloaded, and all guest-generated sparse files removed.
|
||||
@@ -0,0 +1,88 @@
|
||||
# G4 xattr, ACL, and metabox manual setup
|
||||
|
||||
This setup is shared only by TC005, TC067-TC083, TC117, TC134-TC140, and
|
||||
TC142. It does not consume an existing image or report from `/work/build`.
|
||||
|
||||
## Host fixture generation
|
||||
|
||||
The host must provide erofs-utils 1.8.6 and Linux `user.*` xattrs. The helper
|
||||
creates the source trees, invokes `mkfs.erofs`, performs structured on-disk
|
||||
transformations, and then reopens every output to verify its fields and hashes.
|
||||
|
||||
```sh
|
||||
mkfs.erofs -V
|
||||
run=/work/build/repo22-g4-$(date -u +%Y%m%dT%H%M%SZ)
|
||||
python3 tests/g4_fixtures.py make --output "$run"
|
||||
python3 tests/g4_fixtures.py verify --output "$run"
|
||||
sha256sum -c "$run/IMAGE-SHA256SUMS"
|
||||
```
|
||||
|
||||
`mkfs.erofs -V` must report 1.8.6. `SOURCE-SHA256`,
|
||||
`IMAGE-SHA256SUMS`, and `fixture-manifest.json` are required evidence. The
|
||||
manifest records the complete source inventory, each mkfs command, image and
|
||||
provider sizes, and every transformed field as offset/size/before/after bytes.
|
||||
|
||||
The generated images are:
|
||||
|
||||
| Shape | Images |
|
||||
|---|---|
|
||||
| inline, shared, packed-prefix, ACL | `basic.erofs` |
|
||||
| primary prefix fallback | `prefix-primary.erofs` |
|
||||
| plain, compressed, fragment metabox | `metabox-plain.erofs`, `metabox-compressed.erofs`, `metabox-fragment.erofs` |
|
||||
| malformed xattr | `bad-inline-entry.erofs`, `bad-shared-entry.erofs` |
|
||||
| declared bounds | `bad-shared-declared-bounds.erofs`, `bad-prefix-declared-bounds.erofs` |
|
||||
| superblock validation | `bad-metabox-truncated-extension.erofs`, `bad-ishare-prefix-id.erofs` |
|
||||
| fragment safety | `bad-fragment-self-loop.erofs`, `bad-fragment-range.erofs`, `bad-metabox-recursive-nid.erofs`, `bad-packed-recursive-nid.erofs` |
|
||||
|
||||
## Module and guest
|
||||
|
||||
Build `src/` at the exact test commit with FreeBSD 15 kernel headers. Record
|
||||
the commit, header revision/branch, compiler target, `WITH_ZSTDIO`, and KLD
|
||||
SHA256. Copy only the new KLD and generated images to an isolated FreeBSD 15
|
||||
guest. Load the KLD and verify guest hashes before the first case.
|
||||
|
||||
```sh
|
||||
freebsd-version
|
||||
uname -a
|
||||
sha256 /tmp/repo22-g4/erofs.ko /tmp/repo22-g4/images/*.erofs
|
||||
kldload /tmp/repo22-g4/erofs.ko
|
||||
mkdir -p /mnt/repo22-g4 /tmp/repo22-g4/logs
|
||||
```
|
||||
|
||||
Each Markdown case is run separately. Attach its stated image, mount read-only,
|
||||
run only the stated observations, then unmount and detach before the next case.
|
||||
|
||||
```sh
|
||||
unit=$(mdconfig -a -t vnode -f /tmp/repo22-g4/images/IMAGE.erofs)
|
||||
mount -t erofs -o ro /dev/${unit} /mnt/repo22-g4
|
||||
# case-specific commands
|
||||
umount /mnt/repo22-g4
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## FreeBSD xattr and errno rules
|
||||
|
||||
Linux `user.*` appears in FreeBSD namespace `user` without `user.` in the
|
||||
attribute name. Linux `trusted.*`, `security.*`, and POSIX ACL xattrs appear in
|
||||
FreeBSD namespace `system`; trusted/security retain their full names, while ACL
|
||||
names are `posix_acl_access` and `posix_acl_default`. Use `lsextattr` and
|
||||
`getextattr`, not Linux `getfattr` syntax.
|
||||
|
||||
Use `getextattr -qq -x` for byte-exact output. The utility's exit status is not
|
||||
authoritative for all failures, so capture the kernel result with `truss` and
|
||||
require errno 87 (`ENOATTR`), 97 (`EINTEGRITY`), 5 (`EIO`), or 30 (`EROFS`) as
|
||||
specified by the case. Negative mounts must show `nmount(...)=ERR#97` or an
|
||||
equivalent normalized `EIO` at a boundary where the VFS maps integrity errors.
|
||||
|
||||
## Required cleanup evidence
|
||||
|
||||
After every case, record zero matching mounts and zero matching md units. At
|
||||
the end, require no active EROFS allocation, unload the KLD, and stop the
|
||||
dedicated VM.
|
||||
|
||||
```sh
|
||||
mount | grep repo22-g4 || true
|
||||
mdconfig -l
|
||||
vmstat -m | grep erofs
|
||||
kldunload erofs
|
||||
```
|
||||
@@ -0,0 +1,118 @@
|
||||
# G5 Compression Manual Setup
|
||||
|
||||
This is the canonical fixture and execution contract for exactly these 24
|
||||
tests:
|
||||
|
||||
`TC003`, `TC004`, `TC084`-`TC092`, `TC102`-`TC110`, and `TC143`-`TC146`.
|
||||
|
||||
The commands and paths here replace placeholder image names, blind corruption
|
||||
offsets, and non-source-compared reads in the individual test descriptions.
|
||||
Do not use old images or reports as fixture inputs.
|
||||
|
||||
## Host fixture generation
|
||||
|
||||
Requirements are `mkfs.erofs`, `dump.erofs`, and `fsck.erofs` 1.8.6. Generate
|
||||
into a new path; the helper rejects an existing output directory.
|
||||
|
||||
```sh
|
||||
out=/work/build/repo22-g5-fixtures-a
|
||||
python3 tests/g5_fixtures.py create \
|
||||
--output "$out" \
|
||||
--erofs-utils-source /path/to/erofs-utils-1.8.6
|
||||
python3 tests/g5_fixtures.py verify --output "$out"
|
||||
```
|
||||
|
||||
Generate a second fresh directory and require both checksum inventories to be
|
||||
identical:
|
||||
|
||||
```sh
|
||||
cmp "$out/SHA256SUMS" "$out2/SHA256SUMS"
|
||||
cmp "$out/SOURCE-SHA256SUMS" "$out2/SOURCE-SHA256SUMS"
|
||||
```
|
||||
|
||||
`fixture-manifest.json` records every mkfs option, source and image hash,
|
||||
inode/NID/size/layout, compressed map-header offset, advise bits, algorithm
|
||||
nibbles, extent summaries, partial-reference indexes and physical blocks, and
|
||||
corruption pcluster/patch ranges. Creation reopens every transformed image and
|
||||
the separate `verify` command repeats the structured checks.
|
||||
|
||||
The partial-reference transformer changes the HEAD pblk, sets
|
||||
`Z_EROFS_LI_PARTIAL_REF`, and copies the complete source pcluster's
|
||||
`D0_CBLKCNT`. Corruption is applied only after `dump.erofs` and the byte parser
|
||||
agree on the target algorithm and physical extent.
|
||||
|
||||
## Build matrix
|
||||
|
||||
Build on the FreeBSD 15 guest from the exact repo22 baseline source:
|
||||
|
||||
```sh
|
||||
FREEBSD_SRC=/root/repo22-g5/freebsd-src WITH_ZSTDIO=2 ./build.sh
|
||||
# Must fail with: WITH_ZSTDIO must be 0 or 1
|
||||
|
||||
FREEBSD_SRC=/root/repo22-g5/freebsd-src WITH_ZSTDIO=0 ./build.sh
|
||||
cp build/erofs.ko /root/repo22-g5/erofs-nozstd.ko
|
||||
nm -u /root/repo22-g5/erofs-nozstd.ko
|
||||
|
||||
FREEBSD_SRC=/root/repo22-g5/freebsd-src WITH_ZSTDIO=1 ./build.sh
|
||||
cp build/erofs.ko /root/repo22-g5/erofs-zstdio.ko
|
||||
nm -u /root/repo22-g5/erofs-zstdio.ko
|
||||
```
|
||||
|
||||
The disabled module must have no `ZSTD_*` or `bcmp` reference. The enabled
|
||||
module may reference only the formal FreeBSD ZSTD API names. Load by full path,
|
||||
obtain the file ID from the matching `kldstat` path row, and unload that ID.
|
||||
|
||||
## Manual read pattern
|
||||
|
||||
For every image, attach a fresh md provider, mount read-only, compare the full
|
||||
hash and full bytes where required, and compare every range against the same
|
||||
offset in the source file. `tests/read_probe.c` provides deterministic `pread`
|
||||
and errno checks; it is a probe, not a runner.
|
||||
|
||||
```sh
|
||||
unit=$(mdconfig -a -t vnode -f "$image")
|
||||
mount -t erofs -o ro "/dev/$unit" "$mnt"
|
||||
sha256 -q "$source"
|
||||
sha256 -q "$mnt/$name"
|
||||
cmp "$source" "$mnt/$name"
|
||||
read_probe pread "$mnt/$name" "$offset" "$length" guest.bin
|
||||
read_probe pread "$source" "$offset" "$length" source.bin
|
||||
cmp source.bin guest.bin
|
||||
umount "$mnt"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
Use `timeout 20 read_probe expect-error FILE 5` for compressed-stream
|
||||
corruption. Also compare `control.bin` from the same corrupted image, then
|
||||
require no mount/md remains and EROFS active allocations return to zero.
|
||||
|
||||
## Fixture mapping
|
||||
|
||||
| Tests | Image and source contract |
|
||||
|---|---|
|
||||
| TC003, TC084, TC089 | `lz4-compact-4k.erofs` or `lz4-full-4k.erofs`; `sources/lz4/compressed.bin` |
|
||||
| TC085 | `lz4-large.erofs`; 268435456-byte `sources/large/large.bin` |
|
||||
| TC086, TC087, TC090 | `lz4-compact-64k.erofs`; fixed source offsets |
|
||||
| TC088 | 4K, 64K, and 256K compact LZ4 images; same source bytes |
|
||||
| TC091, TC092 | `lz4-ztail.erofs`; inline target plus four edge controls |
|
||||
| TC004 | `lzma-level6.erofs`; full, middle, and EOF reads |
|
||||
| TC102-TC104 | distinct DEFLATE level 1, 6, and 9 images |
|
||||
| TC105-TC107 | distinct ZSTD level 1, 15, and 22 images |
|
||||
| TC108 | `lzma-large.erofs`; 104857601-byte LZMA level 6 source |
|
||||
| TC109 | `microlzma-edge.erofs`; actual 1B, 4K, and compressed 16K files |
|
||||
| TC110, TC144 | LZMA partial/corrupt pair plus same-image `control.bin` |
|
||||
| TC143 | DEFLATE and ZSTD partial/corrupt pairs plus controls |
|
||||
| TC145 | both KLDs, LZ4 control, and `zstd-level1.erofs` gate/read |
|
||||
| TC146 HEAD2 | `head2.erofs` and targeted corrupt copy; boundary from manifest |
|
||||
| TC146 interlaced | `interlaced.erofs`; first compressed/plain transition from manifest |
|
||||
| TC146 explicit extent | `extent-attempt.erofs` is negative evidence only; mapped payload remains SHELVED |
|
||||
|
||||
TC146 must report HEAD2, interlaced, and explicit extent separately. A normal
|
||||
full-index image produced with `--max-extent-bytes` is not explicit-extent
|
||||
coverage.
|
||||
|
||||
## Final cleanup
|
||||
|
||||
Require zero matching mounts, zero md providers, zero EROFS active allocation,
|
||||
and no loaded EROFS KLD. Compare pre/post dmesg, verify guest responsiveness,
|
||||
power off the dedicated VM, and remove Python bytecode caches before commit.
|
||||
@@ -0,0 +1,164 @@
|
||||
# G6 Chunk and Multi-Device Manual Setup
|
||||
|
||||
This setup applies only to `TC006`, `TC093` through `TC101`, and `TC118`.
|
||||
There are exactly 11 test cases. The commands below generate new inputs; no
|
||||
fixture or result from an earlier run is an input.
|
||||
|
||||
## Host prerequisites
|
||||
|
||||
- Linux host with erofs-utils 1.8.6 (`mkfs.erofs` and `fsck.erofs`).
|
||||
- Python 3.11 or newer.
|
||||
- QEMU with qcow2 support.
|
||||
- A clean FreeBSD 15 amd64 base disk used only as the backing file for a new
|
||||
per-run overlay.
|
||||
|
||||
Set a new run directory and generate the fixtures twice:
|
||||
|
||||
```sh
|
||||
REPO=/path/to/worktree/repo-community/repo22
|
||||
RUN=/work/build/repo22-g6-$(date -u +%Y%m%dT%H%M%SZ)
|
||||
mkdir -p "$RUN"
|
||||
cd "$REPO"
|
||||
python3 -B tests/g6_multidev_fixtures.py generate \
|
||||
--output "$RUN/fixtures-a"
|
||||
python3 -B tests/g6_multidev_fixtures.py generate \
|
||||
--output "$RUN/fixtures-b"
|
||||
cmp "$RUN/fixtures-a/manifest.json" "$RUN/fixtures-b/manifest.json"
|
||||
cmp "$RUN/fixtures-a/SHA256SUMS" "$RUN/fixtures-b/SHA256SUMS"
|
||||
python3 -B tests/g6_multidev_fixtures.py verify "$RUN/fixtures-a"
|
||||
```
|
||||
|
||||
`generate` refuses an existing output directory, fixes source bytes, UUIDs,
|
||||
timestamps, worker count, and every binary transformation, and asserts the
|
||||
old field before each patch. `verify` checks every artifact size and SHA256,
|
||||
then reparses superblock, device-table, and chunk-index fields from disk.
|
||||
|
||||
The manifest records two erofs-utils 1.8.6 limitations. Its fsck qualifies
|
||||
the mkfs split image, single-index image, explicit 2/3-slot images, table-at-0,
|
||||
`uniaddr=0`, fragment image, and original two-block LZ4 pcluster. Flatdev and
|
||||
device-ID-0 unified relocation are qualified by the FreeBSD kernel reads in
|
||||
TC094 and TC101 because this fsck release does not implement those mappings.
|
||||
|
||||
## Dedicated FreeBSD 15 VM
|
||||
|
||||
Create a new overlay and use only SSH port 9226 for this run:
|
||||
|
||||
```sh
|
||||
qemu-img create -f qcow2 -F qcow2 \
|
||||
-b /work/build/vm-freebsd-dev-base.qcow2 \
|
||||
"$RUN/freebsd15-overlay.qcow2"
|
||||
qemu-system-x86_64 -accel tcg,thread=multi -cpu qemu64 \
|
||||
-m 6144 -smp 4 \
|
||||
-drive file="$RUN/freebsd15-overlay.qcow2",if=virtio,format=qcow2 \
|
||||
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:9226-:22 \
|
||||
-device virtio-net-pci,netdev=net0 -display none \
|
||||
-serial file:"$RUN/freebsd15-serial.log" -monitor none \
|
||||
-pidfile "$RUN/freebsd15-qemu.pid" \
|
||||
-D "$RUN/freebsd15-qemu.log" -daemonize
|
||||
```
|
||||
|
||||
Record the guest identity before installing test artifacts:
|
||||
|
||||
```sh
|
||||
uname -a
|
||||
freebsd-version -ku
|
||||
sysctl -n kern.osreldate
|
||||
sha256 /boot/kernel/kernel
|
||||
mdconfig -l
|
||||
mount -p | awk '$3 == "erofs"'
|
||||
```
|
||||
|
||||
The initial `mdconfig` and EROFS mount outputs must be empty.
|
||||
|
||||
## Exact-source KLD
|
||||
|
||||
On the host, record and archive the exact worktree source:
|
||||
|
||||
```sh
|
||||
git rev-parse HEAD | tee "$RUN/source.commit"
|
||||
git status --short
|
||||
git archive --format=tar HEAD repo-community/repo22 | \
|
||||
gzip -n > "$RUN/repo22-source.tar.gz"
|
||||
git archive --format=tar HEAD dev-freebsd-releng/sys | \
|
||||
gzip -n > "$RUN/freebsd-sys-source.tar.gz"
|
||||
tar -C "$RUN/fixtures-a" -czf "$RUN/g6-fixtures.tar.gz" \
|
||||
SHA256SUMS manifest.json images sources
|
||||
```
|
||||
|
||||
Transfer both archives to the new guest. Authentication details remain
|
||||
outside the repository:
|
||||
|
||||
```sh
|
||||
scp -O -P 9226 "$RUN/repo22-source.tar.gz" \
|
||||
"$RUN/freebsd-sys-source.tar.gz" \
|
||||
"$RUN/g6-fixtures.tar.gz" [email protected]:/root/
|
||||
```
|
||||
|
||||
Build natively in the guest, with no source edits:
|
||||
|
||||
```sh
|
||||
mkdir -p /root/freebsd-src /root/repo22-g6-src /root/repo22-g6
|
||||
tar -xzf /root/freebsd-sys-source.tar.gz -C /root/freebsd-src \
|
||||
--strip-components 1
|
||||
tar -xzf /root/repo22-source.tar.gz -C /root/repo22-g6-src \
|
||||
--strip-components 2
|
||||
tar -xzf /root/g6-fixtures.tar.gz -C /root/repo22-g6
|
||||
cd /root/repo22-g6-src
|
||||
grep -E '^(REVISION|BRANCH)=' /root/freebsd-src/sys/conf/newvers.sh
|
||||
env WITH_ZSTDIO=1 FREEBSD_SRC=/root/freebsd-src ./build.sh
|
||||
sha256 build/erofs.ko
|
||||
file build/erofs.ko
|
||||
cp build/erofs.ko /root/repo22-g6/erofs.ko
|
||||
```
|
||||
|
||||
At baseline `6b33b4afb490be7d6fec70e499469c306a58435d`, the tracked sys tree is
|
||||
15.0-RELEASE-p9 and the clean guest is p8; both report OSREL 1500068. Record
|
||||
this source/guest distinction rather than claiming they are the same patch
|
||||
level. Also record `source.commit`, `WITH_ZSTDIO=1`, FreeBSD source archive
|
||||
SHA256, KLD SHA256, kernel SHA256, and all guest values in the report.
|
||||
|
||||
## Manual evidence rules
|
||||
|
||||
Run the commands in each TC Markdown directly. Do not use a runner, CI job,
|
||||
or test wrapper. Before each test:
|
||||
|
||||
```sh
|
||||
mkdir -p /mnt/g6
|
||||
kldload /root/repo22-g6/erofs.ko
|
||||
dmesg | tail -40 > /tmp/g6-dmesg-before
|
||||
```
|
||||
|
||||
For a negative mount or read, capture the syscall result with `truss` and
|
||||
record the named errno, not only command exit status:
|
||||
|
||||
```sh
|
||||
truss -f -o /tmp/operation.truss command arguments
|
||||
tail -20 /tmp/operation.truss
|
||||
```
|
||||
|
||||
After every TC, unmount first, detach external providers in descending slot
|
||||
order, detach the primary, and unload the module. All four checks must report
|
||||
zero:
|
||||
|
||||
```sh
|
||||
mount -p | awk '$3 == "erofs" { print }'
|
||||
mdconfig -l
|
||||
kldstat -n erofs 2>/dev/null || true
|
||||
sysctl -n kern.geom.conftxt | \
|
||||
awk '/Geom name: md9[0-3]$|Consumers:|Providers:|erofs/ { print }'
|
||||
```
|
||||
|
||||
Also compare the new dmesg suffix and reject any panic, trap, assertion,
|
||||
watchdog, or EROFS error not expected by the current negative operation.
|
||||
|
||||
## FreeBSD and Linux behavior
|
||||
|
||||
Linux EROFS accepts a device table at byte offset zero and excludes a slot
|
||||
whose `uniaddr` is zero from device-ID-0 unified lookup; a nonzero device ID
|
||||
still selects that slot. FreeBSD uses explicit `device.<slot>=/dev/<provider>`
|
||||
mount options because GEOM providers are not discovered from Linux block
|
||||
device tags. FreeBSD also holds one read-only GEOM consumer per provider, so
|
||||
normal `mdconfig -d` returns `EBUSY` while mounted. A forced GEOM orphan makes
|
||||
later cold I/O return `ENXIO`; unmount must still release vnode, cdev, and GEOM
|
||||
references. These lifecycle details have no direct Linux loop-device
|
||||
equivalent and are checked in TC006 and TC118.
|
||||
@@ -0,0 +1,226 @@
|
||||
# G7 Boundary and Stress Manual Setup
|
||||
|
||||
This setup applies to exactly `TC120` through `TC130`: 11 tests, with no
|
||||
additional test IDs. Run each test's Markdown commands directly. Do not use a
|
||||
CI job, runner, or test wrapper.
|
||||
|
||||
## Deterministic fixtures
|
||||
|
||||
The host requires Python 3, erofs-utils 1.8.6, GNU tar, QEMU, and at least
|
||||
2 GiB of free working space. Generate two fresh fixture directories; the
|
||||
helper rejects an existing output path.
|
||||
|
||||
```sh
|
||||
REPO=/path/to/worktree/repo-community/repo22
|
||||
RUN=/work/build/repo22-g7-$(date -u +%Y%m%dT%H%M%SZ)
|
||||
mkdir -p "$RUN"
|
||||
cd "$REPO"
|
||||
python3 -B tests/g7_fixtures.py create --output "$RUN/fixtures-a"
|
||||
python3 -B tests/g7_fixtures.py create --output "$RUN/fixtures-b"
|
||||
python3 -B tests/g7_fixtures.py verify --output "$RUN/fixtures-a"
|
||||
cmp "$RUN/fixtures-a/SOURCE-INVENTORY.tsv" \
|
||||
"$RUN/fixtures-b/SOURCE-INVENTORY.tsv"
|
||||
cmp "$RUN/fixtures-a/SOURCE-SHA256SUMS" \
|
||||
"$RUN/fixtures-b/SOURCE-SHA256SUMS"
|
||||
cmp "$RUN/fixtures-a/SHA256SUMS" "$RUN/fixtures-b/SHA256SUMS"
|
||||
sha256sum "$RUN/fixtures-a/SOURCE-INVENTORY.tsv" \
|
||||
"$RUN/fixtures-a/SOURCE-SHA256SUMS" \
|
||||
"$RUN/fixtures-a/SHA256SUMS" \
|
||||
"$RUN/fixtures-a/fixture-manifest.json"
|
||||
```
|
||||
|
||||
`SOURCE-INVENTORY.tsv` records the exact relative path, size, and SHA256 of
|
||||
every source file. The helper re-hashes the complete inventory, checks exact
|
||||
counts and names, checks all sparse markers and allocated-block usage, runs
|
||||
`fsck.erofs`, reopens the 4 GiB boundary inode with `dump.erofs`, and verifies
|
||||
the image checksums. `boundaries.erofs` covers TC120-TC125;
|
||||
`workloads.erofs` covers TC126-TC130.
|
||||
|
||||
The practical sparse boundary is 4 GiB + 4097 bytes. It crosses signed 32-bit,
|
||||
2 GiB, unsigned 32-bit, 4 GiB, block, hole, and EOF boundaries without
|
||||
claiming that a 16 TiB image is practical in this VM. The source remains
|
||||
sparse and every selected range is compared to that exact source in TC121.
|
||||
|
||||
## Dedicated FreeBSD 15 VM
|
||||
|
||||
Create a new qcow2 overlay and use only SSH port 9227:
|
||||
|
||||
```sh
|
||||
qemu-img create -f qcow2 -F qcow2 \
|
||||
-b /work/build/vm-freebsd-dev-base.qcow2 \
|
||||
"$RUN/freebsd15-overlay.qcow2"
|
||||
qemu-system-x86_64 -accel tcg,thread=multi -cpu qemu64 \
|
||||
-m 6144 -smp 4 \
|
||||
-drive file="$RUN/freebsd15-overlay.qcow2",if=virtio,format=qcow2 \
|
||||
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:9227-:22 \
|
||||
-device virtio-net-pci,netdev=net0 -display none \
|
||||
-serial file:"$RUN/freebsd15-serial.log" -monitor none \
|
||||
-pidfile "$RUN/freebsd15-qemu.pid" \
|
||||
-D "$RUN/freebsd15-qemu.log" -daemonize
|
||||
```
|
||||
|
||||
Record the initial guest identity and resource-control state:
|
||||
|
||||
```sh
|
||||
uname -a
|
||||
freebsd-version -ku
|
||||
sysctl -n kern.osreldate
|
||||
sha256 /boot/kernel/kernel
|
||||
sysctl kern.racct.enable
|
||||
rctl
|
||||
vmstat -H 1 3
|
||||
mdconfig -l
|
||||
mount -p | awk '$3 == "erofs"'
|
||||
```
|
||||
|
||||
If RACCT/RCTL is disabled, enable the FreeBSD loader tunable in this overlay
|
||||
and reboot it. Do not use a jail as a memory-limit command.
|
||||
|
||||
```sh
|
||||
grep -q '^kern.racct.enable=' /boot/loader.conf || \
|
||||
printf 'kern.racct.enable="1"\n' >> /boot/loader.conf
|
||||
grep '^kern.racct.enable=' /boot/loader.conf
|
||||
shutdown -r now
|
||||
```
|
||||
|
||||
After reconnecting, require `sysctl -n kern.racct.enable` to print `1` and
|
||||
record `rctl` plus `vmstat -H 1 3` again.
|
||||
|
||||
## Exact-source KLD and guest inputs
|
||||
|
||||
Commit the helper and corrected Markdown before building. Then archive the
|
||||
exact commit and the tracked FreeBSD 15 sys tree. The final report may be a
|
||||
later documentation-only commit, but its `repo22/src` tree hash must equal the
|
||||
build input tree hash.
|
||||
|
||||
```sh
|
||||
cd /path/to/worktree
|
||||
BUILD_COMMIT=$(git rev-parse HEAD)
|
||||
git status --short
|
||||
printf '%s\n' "$BUILD_COMMIT" > "$RUN/source.commit"
|
||||
git rev-parse "$BUILD_COMMIT:repo-community/repo22/src" \
|
||||
> "$RUN/repo22-src.tree"
|
||||
git archive --format=tar "$BUILD_COMMIT" repo-community/repo22 | \
|
||||
gzip -n > "$RUN/repo22-source.tar.gz"
|
||||
git archive --format=tar "$BUILD_COMMIT" dev-freebsd-releng/sys | \
|
||||
gzip -n > "$RUN/freebsd-sys-source.tar.gz"
|
||||
tar --sparse --format=gnu -C "$RUN/fixtures-a" \
|
||||
-cf "$RUN/boundaries-source.tar" sources/boundaries
|
||||
tar --sparse --format=gnu -C "$RUN/fixtures-a" \
|
||||
-cf "$RUN/workloads-source.tar" sources/workloads
|
||||
gzip -n "$RUN/boundaries-source.tar"
|
||||
gzip -n "$RUN/workloads-source.tar"
|
||||
sha256sum "$RUN/repo22-source.tar.gz" \
|
||||
"$RUN/freebsd-sys-source.tar.gz" \
|
||||
"$RUN/boundaries-source.tar.gz" \
|
||||
"$RUN/workloads-source.tar.gz" > "$RUN/source-archives.sha256"
|
||||
```
|
||||
|
||||
Transfer the archives, images, and fixture metadata to the dedicated guest.
|
||||
Authentication configuration stays outside the repository.
|
||||
|
||||
```sh
|
||||
ssh -p 9227 [email protected] 'mkdir -p /root/repo22-g7-transfer'
|
||||
scp -O -P 9227 "$RUN/repo22-source.tar.gz" \
|
||||
"$RUN/freebsd-sys-source.tar.gz" \
|
||||
"$RUN/boundaries-source.tar.gz" "$RUN/workloads-source.tar.gz" \
|
||||
"$RUN/fixtures-a/images/boundaries.erofs" \
|
||||
"$RUN/fixtures-a/images/workloads.erofs" \
|
||||
"$RUN/fixtures-a/SOURCE-INVENTORY.tsv" \
|
||||
"$RUN/fixtures-a/SOURCE-SHA256SUMS" \
|
||||
"$RUN/fixtures-a/SHA256SUMS" \
|
||||
"$RUN/fixtures-a/fixture-manifest.json" \
|
||||
"$RUN/fixtures-a/DEEP-PATH" "$RUN/fixtures-a/LONG-NAME" \
|
||||
"$RUN/fixtures-a/SPARSE-RANGES.tsv" \
|
||||
"$RUN/source.commit" "$RUN/repo22-src.tree" \
|
||||
"$RUN/source-archives.sha256" \
|
||||
[email protected]:/root/repo22-g7-transfer/
|
||||
```
|
||||
|
||||
Build and verify natively in the guest:
|
||||
|
||||
```sh
|
||||
mkdir -p /root/freebsd-src /root/repo22-g7-src \
|
||||
/root/repo22-g7/fixtures/images /root/repo22-g7/fixtures/sources \
|
||||
/root/repo22-g7/evidence
|
||||
tar -xzf /root/repo22-g7-transfer/freebsd-sys-source.tar.gz \
|
||||
-C /root/freebsd-src --strip-components 1
|
||||
tar -xzf /root/repo22-g7-transfer/repo22-source.tar.gz \
|
||||
-C /root/repo22-g7-src --strip-components 2
|
||||
tar -xzf /root/repo22-g7-transfer/boundaries-source.tar.gz \
|
||||
-C /root/repo22-g7/fixtures
|
||||
tar -xzf /root/repo22-g7-transfer/workloads-source.tar.gz \
|
||||
-C /root/repo22-g7/fixtures
|
||||
cp /root/repo22-g7-transfer/*.erofs /root/repo22-g7/fixtures/images/
|
||||
cp /root/repo22-g7-transfer/SOURCE-INVENTORY.tsv \
|
||||
/root/repo22-g7-transfer/SOURCE-SHA256SUMS \
|
||||
/root/repo22-g7-transfer/SHA256SUMS \
|
||||
/root/repo22-g7-transfer/fixture-manifest.json \
|
||||
/root/repo22-g7-transfer/DEEP-PATH \
|
||||
/root/repo22-g7-transfer/LONG-NAME \
|
||||
/root/repo22-g7-transfer/SPARSE-RANGES.tsv \
|
||||
/root/repo22-g7/fixtures/
|
||||
cd /root/repo22-g7/fixtures
|
||||
sha256sum -c SHA256SUMS
|
||||
sha256sum -c SOURCE-SHA256SUMS
|
||||
stat -f 'size=%z blocks=%b blocksize=%k name=%N' \
|
||||
sources/boundaries/maximum/sparse-boundary.bin
|
||||
cd /root/repo22-g7-src
|
||||
grep -E '^(REVISION|BRANCH)=' /root/freebsd-src/sys/conf/newvers.sh
|
||||
env WITH_ZSTDIO=1 FREEBSD_SRC=/root/freebsd-src ./build.sh
|
||||
cp build/erofs.ko /root/repo22-g7/erofs.ko
|
||||
cc -std=c11 -O2 -Wall -Wextra -Werror \
|
||||
-o /root/repo22-g7/g7_probe tests/g7_probe.c
|
||||
sha256 /root/repo22-g7/erofs.ko /root/repo22-g7/g7_probe
|
||||
file /root/repo22-g7/erofs.ko
|
||||
```
|
||||
|
||||
Record the build commit, source tree hash, `WITH_ZSTDIO=1`, archive hashes,
|
||||
FreeBSD source `REVISION`/`BRANCH`, KLD SHA256, probe SHA256, guest identity,
|
||||
kernel SHA256, and TCG/QEMU configuration in the report.
|
||||
|
||||
## Manual lifecycle
|
||||
|
||||
Load the exact module by full path and record its file ID and pathname:
|
||||
|
||||
```sh
|
||||
kldload /root/repo22-g7/erofs.ko
|
||||
kldstat -v | tee /root/repo22-g7/evidence/kldstat-loaded.txt
|
||||
KLD_ID=$(kldstat -v | awk '$NF == "(/root/repo22-g7/erofs.ko)" { print $1 }')
|
||||
test -n "$KLD_ID"
|
||||
printf '%s\n' "$KLD_ID" > /root/repo22-g7/evidence/kld.id
|
||||
dmesg > /root/repo22-g7/evidence/dmesg-before.txt
|
||||
```
|
||||
|
||||
Each TC attaches one fresh vnode-backed md provider, mounts read-only, records
|
||||
all correctness and metrics evidence, unmounts, detaches that exact provider,
|
||||
and verifies both are gone. Never use `killall`; concurrent tests persist
|
||||
every child PID, wait every child, and record every exit code.
|
||||
|
||||
TC128 and TC129 metrics are recording-only under QEMU TCG. Their PASS gate is
|
||||
read completion and exact source hash/byte comparison, not a fixed MB/s,
|
||||
IOPS, or latency threshold. TC127 uses FreeBSD RCTL `vmemoryuse:deny` with
|
||||
cooperating allocation probes, records allocation failure and reclamation,
|
||||
and verifies reads while pressure is held.
|
||||
|
||||
## Final cleanup
|
||||
|
||||
After TC130, require zero child processes, EROFS mounts, md providers, and
|
||||
RCTL rules created by G7. Unload the exact KLD file ID, compare dmesg, and
|
||||
power off the dedicated guest.
|
||||
|
||||
```sh
|
||||
mount -p | awk '$3 == "erofs" { print }'
|
||||
mdconfig -l
|
||||
rctl
|
||||
kldstat -v | grep -A2 -B2 '/root/repo22-g7/erofs.ko'
|
||||
KLD_ID=$(cat /root/repo22-g7/evidence/kld.id)
|
||||
kldunload -i "$KLD_ID"
|
||||
test -z "$(kldstat -v | grep '/root/repo22-g7/erofs.ko')"
|
||||
dmesg > /root/repo22-g7/evidence/dmesg-after.txt
|
||||
shutdown -p now
|
||||
```
|
||||
|
||||
Remove the host overlay, QEMU logs/PID file, source tars, temporary sparse
|
||||
probe data, and Python bytecode caches only after evidence has been copied
|
||||
into the committed report. Confirm port 9227 is released.
|
||||
@@ -0,0 +1,229 @@
|
||||
# Test Result Summary Template
|
||||
|
||||
## Test Execution Information
|
||||
- **Date**: YYYY-MM-DD
|
||||
- **Tester**: Name
|
||||
- **FreeBSD Version**: 13.x / 14.x
|
||||
- **Kernel**: uname -a output
|
||||
- **erofs Module Version**: kldstat output
|
||||
- **Test Duration**: X hours Y minutes
|
||||
|
||||
## Overall Statistics
|
||||
```
|
||||
Total Test Cases: 153 executable cases (plus TC000 template)
|
||||
Executed: ___
|
||||
Passed: ___
|
||||
Failed: ___
|
||||
Skipped: ___
|
||||
Blocked: ___
|
||||
|
||||
Pass Rate: ___%
|
||||
```
|
||||
|
||||
## Phase Results
|
||||
|
||||
### Phase 1: Basic Functionality (15 tests)
|
||||
```
|
||||
Passed: ___/15
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 2: Inode & Data Layouts (21 tests)
|
||||
```
|
||||
Passed: ___/21
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 3: Directory & VFS (26 tests)
|
||||
```
|
||||
Passed: ___/26
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 4: Extended Attributes (17 tests)
|
||||
```
|
||||
Passed: ___/17
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 5: Compression (24 tests)
|
||||
```
|
||||
Passed: ___/24
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
|
||||
**LZMA Tests** (repo18 NEW):
|
||||
- TC004: [PASS/FAIL]
|
||||
- TC108: [PASS/FAIL]
|
||||
- TC109: [PASS/FAIL]
|
||||
- TC110: [PASS/FAIL]
|
||||
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 6: Multi-Device (9 tests)
|
||||
```
|
||||
Passed: ___/9
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 7: Error Handling (8 tests)
|
||||
```
|
||||
Passed: ___/8
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 8: Boundary & Stress (11 tests)
|
||||
```
|
||||
Passed: ___/11
|
||||
Failed: ___
|
||||
Critical Issues: ___
|
||||
```
|
||||
|
||||
**Performance Results**:
|
||||
- TC128 (Sequential): ___ MB/s
|
||||
- TC129 (Random): ___ IOPS
|
||||
- TC130 (Mixed): ___ req/s
|
||||
|
||||
Failed Tests:
|
||||
- TC###: Description - Reason
|
||||
|
||||
### Phase 9: Documentation (1 test)
|
||||
```
|
||||
Passed: ___/1
|
||||
Failed: ___
|
||||
```
|
||||
|
||||
## Critical Failures
|
||||
Priority: Critical failures that prevent basic functionality
|
||||
|
||||
| Test ID | Description | Root Cause | Impact | Status |
|
||||
|---------|-------------|------------|--------|--------|
|
||||
| TC### | Brief | Reason | High/Medium/Low | Open/Fixed |
|
||||
|
||||
## Known Issues
|
||||
Non-critical issues or limitations
|
||||
|
||||
| Test ID | Description | Workaround | Severity | Tracked |
|
||||
|---------|-------------|------------|----------|---------|
|
||||
| TC### | Brief | Workaround if any | Medium/Low | Issue #X |
|
||||
|
||||
## Performance Summary
|
||||
| Metric | Result | Baseline | Delta | Status |
|
||||
|--------|--------|----------|-------|--------|
|
||||
| Sequential Read | ___ MB/s | 500 MB/s | ___% | PASS/FAIL |
|
||||
| Random Read | ___ IOPS | 5000 IOPS | ___% | PASS/FAIL |
|
||||
| Large File (10GB) | ___ s | 20 s | ___% | PASS/FAIL |
|
||||
| Many Files (10K) | ___ s | 30 s | ___% | PASS/FAIL |
|
||||
|
||||
## Feature Coverage
|
||||
```
|
||||
Total Features: 65
|
||||
Tested: ___
|
||||
Passed: ___
|
||||
Failed: ___
|
||||
|
||||
Coverage: ___%
|
||||
```
|
||||
|
||||
### Feature Status
|
||||
- [x] Mount operations: PASS
|
||||
- [x] Inode formats: PASS/FAIL
|
||||
- [x] Data layouts: PASS/FAIL
|
||||
- [x] LZ4 compression: PASS/FAIL
|
||||
- [x] DEFLATE compression: PASS/FAIL
|
||||
- [x] zstd compression: PASS/FAIL
|
||||
- [x] **LZMA compression (NEW)**: PASS/FAIL
|
||||
- [x] Extended attributes: PASS/FAIL
|
||||
- [x] Multi-device: PASS/FAIL
|
||||
- [x] Directory operations: PASS/FAIL
|
||||
- [x] VFS integration: PASS/FAIL
|
||||
|
||||
## Regression Check
|
||||
Comparison with repo17 (64 features, 91% complete)
|
||||
|
||||
| Feature | repo17 | repo18 | Status |
|
||||
|---------|--------|--------|--------|
|
||||
| Basic mount | PASS | PASS | No regression |
|
||||
| LZ4 | PASS | PASS | No regression |
|
||||
| DEFLATE | PASS | PASS | No regression |
|
||||
| zstd | PASS | PASS | No regression |
|
||||
| **LZMA** | NOT IMPL | PASS | **NEW** |
|
||||
| ... | ... | ... | ... |
|
||||
|
||||
## repo18 Iteration 1 Validation
|
||||
**Goal**: LZMA compression support
|
||||
|
||||
### LZMA-Specific Results
|
||||
- TC004 (Basic LZMA): [PASS/FAIL]
|
||||
- TC108 (Large file): [PASS/FAIL]
|
||||
- TC109 (MicroLZMA): [PASS/FAIL]
|
||||
- TC110 (Corrupted): [PASS/FAIL]
|
||||
|
||||
**Data Integrity**: [PASS/FAIL]
|
||||
- SHA256 checksums match: [YES/NO]
|
||||
- Random access works: [YES/NO]
|
||||
- Large file (100MB+) decompressed correctly: [YES/NO]
|
||||
|
||||
**Implementation Validation**:
|
||||
- Self-contained decoder (232 lines): [YES/NO]
|
||||
- No external dependencies: [YES/NO]
|
||||
- Unified interface: [YES/NO]
|
||||
|
||||
**Iteration 1 Status**: [COMPLETE/INCOMPLETE]
|
||||
|
||||
## System Stability
|
||||
- Kernel panics: [YES/NO] - Count: ___
|
||||
- Memory leaks: [DETECTED/NONE]
|
||||
- File descriptor leaks: [DETECTED/NONE]
|
||||
- dmesg errors: [COUNT]
|
||||
|
||||
## Test Environment
|
||||
```
|
||||
CPU: ___
|
||||
Memory: ___ GB
|
||||
Disk: ___ (type)
|
||||
Load during tests: ___
|
||||
```
|
||||
|
||||
## Recommendations
|
||||
1. [Action item 1]
|
||||
2. [Action item 2]
|
||||
3. ...
|
||||
|
||||
## Sign-Off
|
||||
- [ ] All critical tests passed
|
||||
- [ ] No regressions from repo17
|
||||
- [ ] LZMA implementation validated (repo18 iter 1)
|
||||
- [ ] Performance acceptable
|
||||
- [ ] Known issues documented
|
||||
|
||||
**Tested by**: _______________
|
||||
**Reviewed by**: _______________
|
||||
**Date**: _______________
|
||||
**Approved**: [YES/NO]
|
||||
|
||||
## Attachments
|
||||
- [ ] Full test logs
|
||||
- [ ] dmesg output
|
||||
- [ ] Performance graphs
|
||||
- [ ] Failure screenshots/dumps
|
||||
@@ -0,0 +1,36 @@
|
||||
# Test Case Template
|
||||
|
||||
**Test ID**: TC###-brief-name
|
||||
**Category**: [Mount Operations | Filesystem Metadata | Inode Operations | Data Layouts | Compression | Directory Operations | Symlink Operations | Extended Attributes | Multi-Device | VFS Integration | Read-Only Enforcement | VM Integration | Error Handling | Performance & Stress]
|
||||
**Priority**: [Critical | High | Medium | Low]
|
||||
**Regression**: [None | Issue #XXX]
|
||||
|
||||
## Objective
|
||||
Brief description of what this test validates.
|
||||
|
||||
## Preconditions
|
||||
- EROFS image requirements (e.g., "Image with LZ4-compressed files")
|
||||
- System requirements (e.g., "FreeBSD 13.0+")
|
||||
- Test data setup
|
||||
|
||||
## Test Steps
|
||||
1. Step one with specific commands
|
||||
2. Step two with expected intermediate state
|
||||
3. ...
|
||||
|
||||
## Expected Results
|
||||
- Specific expected outcomes
|
||||
- Expected output values
|
||||
- Expected file contents
|
||||
|
||||
## Verification Method
|
||||
How to verify the test passed:
|
||||
- Command outputs to check
|
||||
- Files to inspect
|
||||
- Performance metrics (if applicable)
|
||||
|
||||
## Cleanup
|
||||
Steps to reset the environment after the test.
|
||||
|
||||
## Notes
|
||||
Any additional considerations or known limitations.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Test Case: Basic Mount and Unmount
|
||||
|
||||
**Test ID**: TC001-mount-basic
|
||||
|
||||
## Objective
|
||||
|
||||
Verify that the exact G1 KLD mounts a valid image read-only, exposes source
|
||||
data exactly, and unmounts cleanly.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs` and `source/compact/root.txt` generated by
|
||||
`tests/prepare_g1_fixtures.sh`. Follow `tests/G1-MANUAL-SETUP.md` and record the
|
||||
image, source, and KLD SHA256 values.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
image=/tmp/repo22-g1/images/compact.erofs
|
||||
source=/tmp/repo22-g1/source/compact/root.txt
|
||||
mnt=/mnt/repo22-g1-001
|
||||
md=$(mdconfig -a -t vnode -f "$image")
|
||||
mkdir -p "$mnt"
|
||||
kldstat | grep -i erofs
|
||||
mount -t erofs -o ro "/dev/$md" "$mnt"
|
||||
mount -p | awk -v p="$mnt" '$2 == p'
|
||||
cmp "$source" "$mnt/root.txt"
|
||||
sha256 "$source" "$mnt/root.txt"
|
||||
./statfs_probe "$mnt"
|
||||
umount "$mnt"
|
||||
mdconfig -d -u "${md#md}"
|
||||
rmdir "$mnt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Mount, `cmp`, `statfs_probe`, unmount, and detach all return zero.
|
||||
- The mount entry is `erofs` and read-only; both file hashes are identical.
|
||||
- Cleanup leaves neither this mount point nor its md provider.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Test Case: Superblock CRC32C Validation
|
||||
|
||||
**Test ID**: TC002-superblock-crc32c
|
||||
**Category**: Filesystem Metadata
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the real EROFS superblock checksum field and both equivalent checksum
|
||||
ranges, then prove that a valid image mounts while an equal-length image with
|
||||
one covered byte changed and no checksum update is rejected.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
Run from the repo22 root with erofs-utils 1.8.6:
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc002.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
python3 tests/erofs_fixture.py inspect "$work/fixtures/valid-plain.erofs"
|
||||
python3 tests/erofs_fixture.py inspect "$work/fixtures/bad-super-crc.erofs"
|
||||
grep '^bad-super-crc ' "$work/fixtures/fixture-evidence.txt"
|
||||
(cd "$work/fixtures" && sha256 -c SHA256SUMS)
|
||||
```
|
||||
|
||||
For a 4096-byte block, the canonical calculation clears the little-endian
|
||||
checksum at absolute byte 1028 and calculates CRC32C over bytes `[1024,4096)`
|
||||
with initial value `0xffffffff`. The production verifier uses seed
|
||||
`0x5045b54a` over `[1032,4096)`. The helper must print identical canonical and
|
||||
kernel values, `equivalent=True`, and `valid=True` for the control. The bad
|
||||
image changes byte 1088, preserves provider length, does not recompute CRC, and
|
||||
must print `valid=False`.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
```sh
|
||||
mkdir "$work/mnt"
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/valid-plain.erofs")
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt"
|
||||
cmp "$work/fixtures/source/control.txt" "$work/mnt/control.txt"
|
||||
umount "$work/mnt"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/bad-super-crc.erofs")
|
||||
set +e
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt" \
|
||||
>"$work/bad-mount.out" 2>"$work/bad-mount.err"
|
||||
mount_status=$?
|
||||
set -e
|
||||
printf 'mount_status=%s\n' "$mount_status"
|
||||
test "$mount_status" -ne 0
|
||||
set +e
|
||||
truss -o "$work/bad-mount.truss" mount -t erofs -o ro "/dev/$unit" \
|
||||
"$work/mnt" >/dev/null 2>&1
|
||||
set -e
|
||||
grep -E 'nmount.*ERR#97' "$work/bad-mount.truss"
|
||||
! mount -p | awk -v path="$work/mnt" '$2 == path { found=1 }
|
||||
END { exit found ? 0 : 1 }'
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
The control mounts and reads exactly. The bad image fails with FreeBSD errno
|
||||
97 (`EINTEGRITY`) and no mount remains. Record both image hashes, provider
|
||||
lengths, checksum values/ranges, command status, new dmesg lines, and cleanup.
|
||||
@@ -0,0 +1,87 @@
|
||||
# Test Case: LZ4 Compressed File Read
|
||||
|
||||
**Test ID**: TC003-lz4-compressed-read
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: Critical
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify correct decompression and reading of LZ4-compressed files.
|
||||
|
||||
## Preconditions
|
||||
- EROFS image with LZ4-compressed files: `test-lz4.erofs`
|
||||
- Known reference file: `original.txt` (uncompressed source)
|
||||
- Compressed file in image: `/compressed/test.txt`
|
||||
- Mount point: `/mnt/test`
|
||||
|
||||
## Test Steps
|
||||
1. Mount the LZ4 test image:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test
|
||||
```
|
||||
|
||||
2. Verify file exists:
|
||||
```
|
||||
ls -lh /mnt/test/compressed/test.txt
|
||||
```
|
||||
|
||||
3. Read the entire file:
|
||||
```
|
||||
cat /mnt/test/compressed/test.txt > /tmp/decompressed.txt
|
||||
```
|
||||
|
||||
4. Calculate checksum:
|
||||
```
|
||||
sha256 /tmp/decompressed.txt
|
||||
sha256 original.txt
|
||||
```
|
||||
|
||||
5. Compare byte-for-byte:
|
||||
```
|
||||
cmp /tmp/decompressed.txt original.txt
|
||||
```
|
||||
|
||||
6. Test partial read:
|
||||
```
|
||||
dd if=/mnt/test/compressed/test.txt of=/tmp/partial.txt bs=1024 count=1
|
||||
```
|
||||
|
||||
7. Verify partial read matches:
|
||||
```
|
||||
cmp -n 1024 /tmp/partial.txt original.txt
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 1: Mount succeeds
|
||||
- Step 2: File size matches original uncompressed size
|
||||
- Step 4: SHA256 checksums are identical
|
||||
- Step 5: `cmp` returns 0 (files identical)
|
||||
- Step 7: First 1024 bytes match
|
||||
|
||||
## Verification Method
|
||||
- Exact byte-for-byte match with original file
|
||||
- No corruption in decompressed data
|
||||
- File attributes (size, timestamps) preserved correctly
|
||||
- Check inode compression format:
|
||||
```
|
||||
# Using custom debug tool if available
|
||||
erofs_inspect /dev/md0 /compressed/test.txt
|
||||
# Should show: z_algorithmformat[0:2] = Z_EROFS_COMPRESSION_LZ4
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u md0
|
||||
rm /tmp/decompressed.txt /tmp/partial.txt
|
||||
```
|
||||
|
||||
## Notes
|
||||
- LZ4 is the most common compression algorithm in EROFS
|
||||
- Test should cover files of various sizes: small (<4KB), medium (4KB-1MB), large (>1MB)
|
||||
- LZ4 pcluster size is typically 4KB or 64KB
|
||||
- Related: TC004 (ztailpacking), TC005 (pcluster mapping)
|
||||
@@ -0,0 +1,96 @@
|
||||
# Test Case: LZMA Compressed File Read
|
||||
|
||||
**Test ID**: TC004-lzma-compressed-read
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify correct decompression and reading of LZMA/MicroLZMA-compressed files (newly implemented in repo18 iteration 1).
|
||||
|
||||
## Preconditions
|
||||
- EROFS image with LZMA-compressed files: `test-lzma.erofs`
|
||||
- Known reference file: `original-large.txt` (uncompressed source)
|
||||
- Compressed file in image: `/compressed/large.txt`
|
||||
- Mount point: `/mnt/test`
|
||||
|
||||
## Test Steps
|
||||
1. Mount the LZMA test image:
|
||||
```sh
|
||||
unit=$(mdconfig -a -t vnode -f test-lzma.erofs)
|
||||
mount -t erofs -o ro /dev/${unit} /mnt/test
|
||||
```
|
||||
|
||||
2. Verify file exists and check size:
|
||||
```
|
||||
ls -lh /mnt/test/compressed/large.txt
|
||||
stat -f "Size: %z bytes" /mnt/test/compressed/large.txt
|
||||
```
|
||||
|
||||
3. Read entire compressed file:
|
||||
```
|
||||
cat /mnt/test/compressed/large.txt > /tmp/lzma-decompressed.txt
|
||||
```
|
||||
|
||||
4. Verify decompression correctness:
|
||||
```
|
||||
sha256 /tmp/lzma-decompressed.txt
|
||||
sha256 original-large.txt
|
||||
```
|
||||
|
||||
5. Compare byte-for-byte:
|
||||
```
|
||||
cmp /tmp/lzma-decompressed.txt original-large.txt
|
||||
echo $?
|
||||
```
|
||||
|
||||
6. Test random access read:
|
||||
```
|
||||
dd if=/mnt/test/compressed/large.txt of=/tmp/lzma-middle.txt bs=1k skip=100 count=10
|
||||
dd if=original-large.txt of=/tmp/orig-middle.txt bs=1k skip=100 count=10
|
||||
cmp /tmp/lzma-middle.txt /tmp/orig-middle.txt
|
||||
```
|
||||
|
||||
7. Test end-of-file read:
|
||||
```
|
||||
tail -c 1000 /mnt/test/compressed/large.txt > /tmp/lzma-tail.txt
|
||||
tail -c 1000 original-large.txt > /tmp/orig-tail.txt
|
||||
cmp /tmp/lzma-tail.txt /tmp/orig-tail.txt
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 1: Mount succeeds
|
||||
- Step 2: File size matches original uncompressed size exactly
|
||||
- Step 4: SHA256 checksums are identical
|
||||
- Step 5: Exit code 0 (files identical)
|
||||
- Step 6: Middle section matches (random access works)
|
||||
- Step 7: Tail matches (EOF handling correct)
|
||||
|
||||
## Verification Method
|
||||
- Complete data integrity check via SHA256
|
||||
- Partial read correctness (random access)
|
||||
- No memory corruption or crashes during decompression
|
||||
- Verify LZMA decoder internal state:
|
||||
- 1846 probability models initialized
|
||||
- Range decoder normalization correct
|
||||
- Dictionary buffer within bounds
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u "${unit}"
|
||||
rm /tmp/lzma-*.txt /tmp/orig-*.txt
|
||||
```
|
||||
|
||||
## Notes
|
||||
- **NEW in repo18**: This is the first iteration with LZMA support
|
||||
- LZMA provides maximum compression ratio (~30-50% smaller than LZ4)
|
||||
- MicroLZMA is a variant without header, commonly used in EROFS
|
||||
- Self-contained implementation in `src/decompressor_lzma.c`
|
||||
- Reference implementation: XZ Embedded minimal decoder
|
||||
- Critical test for repo18 iteration 1 validation
|
||||
- Regression marker: First LZMA implementation, high priority for validation
|
||||
@@ -0,0 +1,32 @@
|
||||
# Test Case: Inline user xattrs
|
||||
|
||||
**Test ID**: TC005-inline-xattr-user
|
||||
**Fixture**: `basic.erofs`, `/inline-user`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify inline `user` namespace list/get and binary-value handling on FreeBSD.
|
||||
Generate and qualify the image as described in `G4-MANUAL-SETUP.md`; the
|
||||
manifest must classify `comment` and `special.chars` as inline entries.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
unit=$(mdconfig -a -t vnode -f /tmp/repo22-g4/images/basic.erofs)
|
||||
mount -t erofs -o ro /dev/${unit} /mnt/repo22-g4
|
||||
stat -f 'mode=%Sp size=%z inode=%i' /mnt/repo22-g4/inline-user
|
||||
lsextattr user /mnt/repo22-g4/inline-user
|
||||
getextattr -qq -x user comment /mnt/repo22-g4/inline-user
|
||||
getextattr -qq -x user special.chars /mnt/repo22-g4/inline-user
|
||||
truss -o /tmp/tc005.truss getextattr -qq user missing /mnt/repo22-g4/inline-user
|
||||
grep extattr_get_file /tmp/tc005.truss
|
||||
umount /mnt/repo22-g4
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The names appear once. `comment` is hex
|
||||
`696e6c696e652d757365722d76616c7565007461696c`; `special.chars` is
|
||||
`7370656369616c2d76616c7565`. The missing name returns `ENOATTR` (87), and
|
||||
cleanup leaves no mount or md provider.
|
||||
@@ -0,0 +1,61 @@
|
||||
# Test Case: Real Multi-Device Chunk Read
|
||||
|
||||
**Test ID**: TC006-multidev-chunk-read
|
||||
**Category**: Multi-Device / Chunk-Based
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Prove that 8-byte chunk indexes read file data from a live external GEOM
|
||||
provider, including a range crossing a chunk boundary.
|
||||
|
||||
## Fixture
|
||||
|
||||
Generate and verify the fresh G6 set as described in `G6-MANUAL-SETUP.md`.
|
||||
Use `mkfs-blob-primary.erofs` and `mkfs-blob-slot1.blob`. The manifest must
|
||||
show primary blocks `1`, slot-1 blocks `224`, and every `/tc006.bin` index as
|
||||
device ID `1`. The 4096-byte primary cannot contain the 98304-byte source.
|
||||
|
||||
## Manual procedure
|
||||
|
||||
```sh
|
||||
I=/root/repo22-g6/images
|
||||
S=/root/repo22-g6/sources/chunk
|
||||
mkdir -p /mnt/g6
|
||||
kldload /root/repo22-g6/erofs.ko
|
||||
mdconfig -a -t vnode -f "$I/mkfs-blob-primary.erofs" -u 90
|
||||
mdconfig -a -t vnode -f "$I/mkfs-blob-slot1.blob" -u 91
|
||||
mount -t erofs -o ro -o device.1=/dev/md91 /dev/md90 /mnt/g6
|
||||
sha256 "$S/tc006.bin" /mnt/g6/tc006.bin
|
||||
cmp "$S/tc006.bin" /mnt/g6/tc006.bin
|
||||
dd if="$S/tc006.bin" of=/tmp/tc006.expected bs=1 skip=28672 count=8192 2>/dev/null
|
||||
dd if=/mnt/g6/tc006.bin of=/tmp/tc006.actual bs=1 skip=28672 count=8192 2>/dev/null
|
||||
cmp /tmp/tc006.expected /tmp/tc006.actual
|
||||
truss -f -o /tmp/tc006-ebusy.truss mdconfig -d -u 91
|
||||
tail -20 /tmp/tc006-ebusy.truss
|
||||
sysctl -n kern.geom.conftxt | grep -A8 -B2 'Geom name: md91'
|
||||
```
|
||||
|
||||
The detach must fail with `EBUSY`, proving a live external consumer.
|
||||
|
||||
## Expected results
|
||||
|
||||
- Mount, full-file `cmp`, SHA256, and the 8192-byte cross-boundary range pass.
|
||||
- The external detach returns exactly `EBUSY` while mounted.
|
||||
- No panic, trap, hang, or unexpected EROFS dmesg message occurs.
|
||||
|
||||
## Cleanup and zero-state check
|
||||
|
||||
```sh
|
||||
umount /mnt/g6
|
||||
mdconfig -d -u 91
|
||||
mdconfig -d -u 90
|
||||
kldunload erofs
|
||||
rm -f /tmp/tc006.expected /tmp/tc006.actual
|
||||
mount -p | awk '$3 == "erofs" { print }'
|
||||
mdconfig -l
|
||||
kldstat -n erofs 2>/dev/null || true
|
||||
sysctl -n kern.geom.conftxt | grep -E 'md9[01]|erofs' || true
|
||||
```
|
||||
|
||||
All four final outputs must be empty.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Test Case: Concurrent Mount Operations
|
||||
|
||||
**Test ID**: TC007-concurrent-mount
|
||||
|
||||
## Objective
|
||||
|
||||
Verify two simultaneous mounts of the same deterministic EROFS image through
|
||||
independent md providers, including source-exact reads from both mounts.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs` and `source/compact/testfile.txt` from the G1
|
||||
fixture set. Follow `tests/G1-MANUAL-SETUP.md`.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
image=/tmp/repo22-g1/images/compact.erofs
|
||||
source=/tmp/repo22-g1/source/compact/testfile.txt
|
||||
mnt1=/mnt/repo22-g1-007a
|
||||
mnt2=/mnt/repo22-g1-007b
|
||||
md1=$(mdconfig -a -t vnode -f "$image")
|
||||
md2=$(mdconfig -a -t vnode -f "$image")
|
||||
mkdir -p "$mnt1" "$mnt2"
|
||||
set +e
|
||||
mount -t erofs -o ro "/dev/$md1" "$mnt1" & p1=$!
|
||||
mount -t erofs -o ro "/dev/$md2" "$mnt2" & p2=$!
|
||||
wait "$p1"; rc1=$?
|
||||
wait "$p2"; rc2=$?
|
||||
set -e
|
||||
printf 'mount_rc=%d,%d providers=%s,%s\n' "$rc1" "$rc2" "$md1" "$md2"
|
||||
test "$rc1" -eq 0 -a "$rc2" -eq 0
|
||||
cmp "$source" "$mnt1/testfile.txt"
|
||||
cmp "$source" "$mnt2/testfile.txt"
|
||||
cmp "$mnt1/testfile.txt" "$mnt2/testfile.txt"
|
||||
sha256 "$source" "$mnt1/testfile.txt" "$mnt2/testfile.txt"
|
||||
umount "$mnt1"
|
||||
umount "$mnt2"
|
||||
mdconfig -d -u "${md1#md}"
|
||||
mdconfig -d -u "${md2#md}"
|
||||
rmdir "$mnt1" "$mnt2"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Both independently waited mount processes return zero.
|
||||
- All three comparisons and SHA256 values match.
|
||||
- No panic, trap, EROFS diagnostic, mount, or md provider remains.
|
||||
@@ -0,0 +1,77 @@
|
||||
# Test Case: Mount Error Conditions
|
||||
|
||||
**Test ID**: TC008-mount-errors
|
||||
**Category**: Mount Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify graceful rejection of three distinct provider conditions: a
|
||||
checksum-valid bad magic at the correct field, a 1023-byte provider ending
|
||||
before the superblock, and a zero-length provider.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc008.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
grep -E '^(bad-magic|truncated-before-super|empty-provider) ' \
|
||||
"$work/fixtures/fixture-evidence.txt"
|
||||
python3 tests/erofs_fixture.py inspect "$work/fixtures/bad-magic.erofs"
|
||||
wc -c "$work/fixtures/bad-magic.erofs" \
|
||||
"$work/fixtures/truncated-before-super.erofs" \
|
||||
"$work/fixtures/empty-provider.erofs"
|
||||
(cd "$work/fixtures" && sha256 -c SHA256SUMS)
|
||||
```
|
||||
|
||||
The bad-magic variant changes only absolute bytes 1024 through 1027 and
|
||||
preserves media size. It intentionally retains the original checksum: the
|
||||
production verifier's fixed-magic suffix calculation remains valid, while the
|
||||
canonical checksum over the now-invalid magic does not. Magic is rejected
|
||||
before checksum verification. The short and empty fixtures are intentional
|
||||
provider-size cases, not same-size corruption variants.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
Create a fresh mount directory. Execute each case separately and record whether
|
||||
failure occurs at `mdconfig` or `nmount`; never assume a fixed md number.
|
||||
|
||||
```sh
|
||||
mkdir "$work/mnt"
|
||||
for image in bad-magic.erofs truncated-before-super.erofs empty-provider.erofs
|
||||
do
|
||||
set +e
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/$image" \
|
||||
2>"$work/$image.md.err")
|
||||
md_status=$?
|
||||
set -e
|
||||
printf '%s md_status=%s unit=%s\n' "$image" "$md_status" "$unit"
|
||||
if test "$md_status" -eq 0; then
|
||||
set +e
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt" \
|
||||
>"$work/$image.out" 2>"$work/$image.mount.err"
|
||||
mount_status=$?
|
||||
set -e
|
||||
printf '%s mount_status=%s\n' "$image" "$mount_status"
|
||||
test "$mount_status" -ne 0
|
||||
set +e
|
||||
truss -o "$work/$image.mount.truss" mount -t erofs -o ro \
|
||||
"/dev/$unit" "$work/mnt" >/dev/null 2>&1
|
||||
set -e
|
||||
grep -E 'nmount.*ERR#' "$work/$image.mount.truss"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
else
|
||||
cat "$work/$image.md.err"
|
||||
fi
|
||||
! mount -p | awk -v path="$work/mnt" '$2 == path { found=1 }
|
||||
END { exit found ? 0 : 1 }'
|
||||
done
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
All three cases fail without panic or hang. Bad magic reaches `nmount` and
|
||||
returns `EINVAL`. A 1023-byte vnode provider reaches `nmount` and returns
|
||||
`ENXIO`; a zero-byte provider is rejected by `mdconfig` with `EINVAL`. Record
|
||||
the observed stage and errno rather than fabricating a mount result. No md unit
|
||||
or mount may remain after each case.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Test Case: Basic statfs Information
|
||||
|
||||
**Test ID**: TC009-statfs-basic
|
||||
|
||||
## Objective
|
||||
|
||||
Verify FreeBSD `statfs(2)` fields against the qualified image superblock.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs`. Before transfer, record `dump.erofs -s` and the
|
||||
`compact` superblock row in `fixture-evidence.txt`. Follow
|
||||
`tests/G1-MANUAL-SETUP.md` and compile `tests/statfs_probe.c` in the guest.
|
||||
|
||||
## Procedure
|
||||
|
||||
Host qualification:
|
||||
|
||||
```sh
|
||||
dump.erofs -s /work/build/repo22-g1/images/compact.erofs
|
||||
python3 tests/erofs_fixture.py inspect /work/build/repo22-g1/images/compact.erofs
|
||||
```
|
||||
|
||||
Guest dynamic check after mounting the image on `$mnt`:
|
||||
|
||||
```sh
|
||||
./statfs_probe "$mnt"
|
||||
df -kT "$mnt"
|
||||
df -iT "$mnt"
|
||||
mount -p | awk -v p="$mnt" '$2 == p'
|
||||
```
|
||||
|
||||
Unmount and detach the exact dynamic md unit.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- `fstype=erofs`, `bsize=4096`, `iosize=4096`, and `readonly=1`.
|
||||
- `blocks` and `files` equal the image's declared block and inode counts.
|
||||
- `bfree`, `bavail`, and `ffree` are zero; `df` conversions agree.
|
||||
- `mount -p` contains `ro`; cleanup succeeds.
|
||||
|
||||
`stat -f` is not a `statfs(2)` probe and must not be substituted.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Test Case: statfs with 48-bit Block Count
|
||||
|
||||
**Test ID**: TC010-statfs-48bit
|
||||
**Category**: Filesystem Metadata
|
||||
**Priority**: Medium
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a nonzero 48-bit block-count high word survives mount validation and is
|
||||
exported without truncation through FreeBSD `statfs(2)` and `df(1)`.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc010.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
python3 tests/erofs_fixture.py inspect \
|
||||
"$work/fixtures/48bit-statfs-prefix.erofs"
|
||||
grep '^48bit-statfs-prefix ' "$work/fixtures/fixture-evidence.txt"
|
||||
sha256 -q "$work/fixtures/48bit-statfs-prefix.erofs"
|
||||
```
|
||||
|
||||
Read `total_blocks` and `required_provider_length` from the evidence. The
|
||||
fixture sets incompat bit `0x80`, `rb.blocks_hi=1`, and a nonzero
|
||||
`rootnid_8b`, then recomputes CRC32C. Its small prefix hash identifies the
|
||||
metadata; the qualified provider is that exact prefix followed by sparse zeros
|
||||
to the required media size.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
```sh
|
||||
provider="$work/48bit-statfs-provider.raw"
|
||||
cp "$work/fixtures/48bit-statfs-prefix.erofs" "$provider"
|
||||
truncate -s "$required_provider_length" "$provider"
|
||||
stat -f 'size=%z blocks=%b' "$provider"
|
||||
unit=$(mdconfig -a -t vnode -f "$provider")
|
||||
diskinfo -v "/dev/$unit"
|
||||
mkdir "$work/mnt"
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt"
|
||||
df -kT "$work/mnt"
|
||||
df -iT "$work/mnt"
|
||||
actual_1k=$(df -k "$work/mnt" | awk 'NR == 2 { print $2 }')
|
||||
used_1k=$(df -k "$work/mnt" | awk 'NR == 2 { print $3 }')
|
||||
avail_1k=$(df -k "$work/mnt" | awk 'NR == 2 { print $4 }')
|
||||
expected_1k=$((total_blocks * 4))
|
||||
test "$actual_1k" -eq "$expected_1k"
|
||||
test "$used_1k" -eq "$expected_1k"
|
||||
test "$avail_1k" -eq 0
|
||||
umount "$work/mnt"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
rm -f "$provider"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
`diskinfo` reports at least the declared 16 TiB-plus media size. Mount succeeds,
|
||||
the `df -k` total equals `total_blocks * 4`, Used equals total because
|
||||
`f_bfree=0`, and Avail is zero.
|
||||
If the filesystem cannot create or attach the sparse provider, record SHELVED
|
||||
with all failed commands; a short-provider `ENXIO` is not PASS.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Test Case: Root Vnode Lookup
|
||||
|
||||
**Test ID**: TC011-root-vnode
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the mounted root vnode has the encoded root NID, directory attributes,
|
||||
and the same top-level names as the fixture source.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs` and `source/compact`. The structured evidence records
|
||||
the root NID and compact inode size. Follow `tests/G1-MANUAL-SETUP.md`.
|
||||
|
||||
## Procedure
|
||||
|
||||
After mounting on `$mnt`:
|
||||
|
||||
```sh
|
||||
stat -f 'ino=%i type=%HT mode=%Lp nlink=%l' "$mnt"
|
||||
stat -f '%i' "$mnt" > /tmp/tc011-root-nid
|
||||
ls -la "$mnt"
|
||||
(cd /tmp/repo22-g1/source/compact && ls -1A | sort) > /tmp/tc011-source-names
|
||||
(cd "$mnt" && ls -1A | sort) > /tmp/tc011-mount-names
|
||||
diff -u /tmp/tc011-source-names /tmp/tc011-mount-names
|
||||
cat "$mnt/root.txt"
|
||||
```
|
||||
|
||||
Compare `/tmp/tc011-root-nid` with `root_nid` from `fixture-evidence.txt`, then
|
||||
unmount, detach, and remove the two temporary name lists.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Root inode equals the encoded NID and reports a traversable directory.
|
||||
- The complete top-level name lists match and `root.txt` is readable.
|
||||
- All operations and cleanup return zero.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Test Case: VFS Vget Normal Operation
|
||||
|
||||
**Test ID**: TC012-vget-normal
|
||||
|
||||
## Objective
|
||||
|
||||
Exercise `VFS_VGET` through a real FreeBSD file handle and verify the returned
|
||||
vnode identifies and reads the same EROFS inode as pathname lookup.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs`, `source/compact/testfile.txt`, and
|
||||
`tests/nfs_fh_tool.c`. Compile the helper as described in
|
||||
`tests/G1-MANUAL-SETUP.md`; run as root.
|
||||
|
||||
## Procedure
|
||||
|
||||
After mounting on `$mnt`:
|
||||
|
||||
```sh
|
||||
stat -f 'path_ino=%i gen=%v size=%z' "$mnt/testfile.txt"
|
||||
./nfs_fh_tool capture "$mnt/testfile.txt" /tmp/tc012-a.fh
|
||||
./nfs_fh_tool capture "$mnt/testfile.txt" /tmp/tc012-b.fh
|
||||
./nfs_fh_tool compare /tmp/tc012-a.fh /tmp/tc012-b.fh
|
||||
./nfs_fh_tool describe /tmp/tc012-a.fh
|
||||
./nfs_fh_tool stat /tmp/tc012-a.fh
|
||||
./nfs_fh_tool cat /tmp/tc012-a.fh /tmp/tc012-fh.out
|
||||
cmp /tmp/repo22-g1/source/compact/testfile.txt /tmp/tc012-fh.out
|
||||
sha256 /tmp/repo22-g1/source/compact/testfile.txt /tmp/tc012-fh.out
|
||||
```
|
||||
|
||||
Remove the handles/output, then unmount and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Both captures produce the same handle.
|
||||
- Handle NID, `fhstat` inode, and pathname inode agree.
|
||||
- `fhopen` output matches the deterministic source exactly.
|
||||
- No stale/duplicate vnode error or cleanup failure occurs.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Test Case: Vget with Invalid NID
|
||||
|
||||
**Test ID**: TC013-vget-invalid
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a checksum-valid directory entry that points outside the image reaches
|
||||
the cold lookup/vget path and fails consistently with `EINTEGRITY`.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/invalid-dirent-nid.erofs`. `fixture-evidence.txt` records the exact
|
||||
dirent offset, old NID, out-of-range NID, and valid recomputed CRC. Compile
|
||||
`tests/read_probe.c` in the guest.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount the image without first listing the root, then run:
|
||||
|
||||
```sh
|
||||
./read_probe expect-error "$mnt/invalid-target.txt" 97
|
||||
./read_probe expect-error "$mnt/invalid-target.txt" 97
|
||||
set +e
|
||||
truss -o /tmp/tc013.truss stat "$mnt/invalid-target.txt"
|
||||
rc=$?
|
||||
set -e
|
||||
printf 'stat_rc=%d\n' "$rc"
|
||||
tail -20 /tmp/tc013.truss
|
||||
```
|
||||
|
||||
Record dmesg before/after, remove the trace, then unmount and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Mount succeeds because only the child dirent is malformed.
|
||||
- Both cold/repeated opens fail at pathname acquisition with FreeBSD errno 97
|
||||
(`EINTEGRITY`); `truss` shows the same syscall errno.
|
||||
- The second failure is not converted to `ENOENT`; no panic or stale vnode
|
||||
appears, and cleanup succeeds.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Test Case: Superblock Parsing
|
||||
|
||||
**Test ID**: TC014-superblock-parse
|
||||
|
||||
## Objective
|
||||
|
||||
Verify mandatory superblock fields at their real on-disk offsets and compare
|
||||
the mounted values exposed by FreeBSD.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs`, its image hash, `fixture-evidence.txt`, and
|
||||
`tests/statfs_probe.c`.
|
||||
|
||||
## Procedure
|
||||
|
||||
Host inspection:
|
||||
|
||||
```sh
|
||||
od -An -tx4 -j 1024 -N 4 /work/build/repo22-g1/images/compact.erofs
|
||||
od -An -tu1 -j 1036 -N 1 /work/build/repo22-g1/images/compact.erofs
|
||||
od -An -tu2 -j 1038 -N 2 /work/build/repo22-g1/images/compact.erofs
|
||||
od -An -tu8 -j 1040 -N 8 /work/build/repo22-g1/images/compact.erofs
|
||||
od -An -tu4 -j 1060 -N 8 /work/build/repo22-g1/images/compact.erofs
|
||||
dump.erofs -s /work/build/repo22-g1/images/compact.erofs
|
||||
python3 tests/erofs_fixture.py inspect /work/build/repo22-g1/images/compact.erofs
|
||||
```
|
||||
|
||||
Mount the same hashed image in FreeBSD, then run:
|
||||
|
||||
```sh
|
||||
./statfs_probe "$mnt"
|
||||
stat -f 'root_ino=%i type=%HT' "$mnt"
|
||||
mount -p | awk -v p="$mnt" '$2 == p'
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Magic is `0xe0f5e1e2`, `blkszbits=12`, and checksum validation is true.
|
||||
- Root NID, block count, and inode count agree with root `stat` and
|
||||
`statfs_probe`; filesystem type is `erofs` and read-only.
|
||||
- No parser error appears in the dmesg delta; cleanup succeeds.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Test Case: Corrupted Superblock Fields
|
||||
|
||||
**Test ID**: TC015-superblock-corrupted
|
||||
**Category**: Error Handling
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify ordered rejection of an unsupported block size, an image-bounds-invalid
|
||||
48-bit root NID, and an unknown incompat feature. Every variant preserves
|
||||
provider length and carries a checksum valid for its encoded fields.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc015.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
grep -E '^(bad-block-size|bad-root-nid|unsupported-feature) ' \
|
||||
"$work/fixtures/fixture-evidence.txt"
|
||||
python3 tests/erofs_fixture.py inspect "$work/fixtures/bad-block-size.erofs"
|
||||
python3 tests/erofs_fixture.py inspect "$work/fixtures/bad-root-nid.erofs"
|
||||
python3 tests/erofs_fixture.py inspect "$work/fixtures/unsupported-feature.erofs"
|
||||
(cd "$work/fixtures" && sha256 -c SHA256SUMS)
|
||||
```
|
||||
|
||||
`bad-block-size` changes `blkszbits` at 1036 from 12 to 13 and recomputes the
|
||||
checksum over `[1024,8192)`. `bad-root-nid` selects the 48-bit union form and
|
||||
sets `rootnid_8b` beyond the declared inode area. `unsupported-feature` sets
|
||||
unknown incompat bit `0x80000000`.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
For each image, attach a dynamic vnode md unit, run mount directly and under
|
||||
`truss`, assert nonzero status and no mount entry, then detach that exact unit.
|
||||
|
||||
```sh
|
||||
mkdir "$work/mnt"
|
||||
for image in bad-block-size.erofs bad-root-nid.erofs unsupported-feature.erofs
|
||||
do
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/$image")
|
||||
set +e
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt" \
|
||||
>"$work/$image.out" 2>"$work/$image.err"
|
||||
status=$?
|
||||
set -e
|
||||
printf '%s status=%s\n' "$image" "$status"
|
||||
test "$status" -ne 0
|
||||
set +e
|
||||
truss -o "$work/$image.truss" mount -t erofs -o ro "/dev/$unit" \
|
||||
"$work/mnt" >/dev/null 2>&1
|
||||
set -e
|
||||
grep -E 'nmount.*ERR#' "$work/$image.truss"
|
||||
! mount -p | awk -v path="$work/mnt" '$2 == path { found=1 }
|
||||
END { exit found ? 0 : 1 }'
|
||||
mdconfig -d -u "${unit#md}"
|
||||
done
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
Bad block size returns `EINVAL`, bad root NID returns `EINTEGRITY`, and the
|
||||
unknown incompat bit returns `EOPNOTSUPP`. Record syscall errno, image hash,
|
||||
provider length, new dmesg lines, and cleanup for all three subcases.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Test Case: Superblock CRC Field Mismatch
|
||||
|
||||
**Test ID**: TC016-superblock-crc-invalid
|
||||
**Category**: Error Handling
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify that changing only the stored superblock checksum field causes
|
||||
`EINTEGRITY`, with all protected bytes and provider length unchanged.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc016.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
grep '^bad-checksum-field ' "$work/fixtures/fixture-evidence.txt"
|
||||
python3 tests/erofs_fixture.py inspect \
|
||||
"$work/fixtures/bad-checksum-field.erofs"
|
||||
wc -c "$work/fixtures/valid-plain.erofs" \
|
||||
"$work/fixtures/bad-checksum-field.erofs"
|
||||
sha256 -q "$work/fixtures/bad-checksum-field.erofs"
|
||||
```
|
||||
|
||||
The mutator flips bit 0 of the little-endian checksum at absolute byte 1028,
|
||||
does not recompute it, asserts checksum invalidity, and changes no other byte.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
```sh
|
||||
mkdir "$work/mnt"
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/bad-checksum-field.erofs")
|
||||
set +e
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt" \
|
||||
>"$work/mount.out" 2>"$work/mount.err"
|
||||
status=$?
|
||||
set -e
|
||||
test "$status" -ne 0
|
||||
set +e
|
||||
truss -o "$work/mount.truss" mount -t erofs -o ro "/dev/$unit" \
|
||||
"$work/mnt" >/dev/null 2>&1
|
||||
set -e
|
||||
grep -E 'nmount.*ERR#97' "$work/mount.truss"
|
||||
! mount -p | awk -v path="$work/mnt" '$2 == path { found=1 }
|
||||
END { exit found ? 0 : 1 }'
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
Mount returns errno 97 (`EINTEGRITY`) with a checksum diagnostic. No mount or
|
||||
md consumer remains.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Test Case: 48-bit Block Count Parsing
|
||||
|
||||
**Test ID**: TC017-48bit-blocks-parse
|
||||
**Category**: Filesystem Metadata
|
||||
**Priority**: Medium
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the Linux EROFS union rule dynamically: with incompat bit `0x80` and a
|
||||
nonzero `rootnid_8b`, combine `blocks_lo` with `rb.blocks_hi << 32` and preserve
|
||||
the complete count through mount.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc017.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
python3 tests/erofs_fixture.py inspect \
|
||||
"$work/fixtures/48bit-statfs-prefix.erofs"
|
||||
od -An -tx2 -j 1038 -N 2 "$work/fixtures/48bit-statfs-prefix.erofs"
|
||||
od -An -tx4 -j 1060 -N 4 "$work/fixtures/48bit-statfs-prefix.erofs"
|
||||
od -An -tx8 -j 1136 -N 8 "$work/fixtures/48bit-statfs-prefix.erofs"
|
||||
grep '^48bit-statfs-prefix ' "$work/fixtures/fixture-evidence.txt"
|
||||
```
|
||||
|
||||
Require `blocks_hi=1`, `rootnid_8b != 0`, a valid recomputed CRC, and a recorded
|
||||
prefix SHA256. The expected count is `blocks_lo | (1 << 32)`.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
Create and attach the sparse provider exactly as in TC010. Record `diskinfo`,
|
||||
mount it read-only, compare `df -k` total with `total_blocks * 4`, read
|
||||
`control.txt`, then unmount and detach the dynamic md unit.
|
||||
|
||||
Also attach the unextended small prefix once and require mount failure with
|
||||
`ENXIO`; record this only as the negative media-size guard, not the positive
|
||||
parse result.
|
||||
|
||||
## Expected Results
|
||||
|
||||
The sparse provider mount succeeds and reports the full nonzero-high-word count.
|
||||
The small prefix fails `ENXIO`. If no qualifying provider can be attached,
|
||||
record the metadata parsing evidence separately and mark the dynamic portion
|
||||
SHELVED, never PASS.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Test Case: Large Filesystem with 48-bit Addressing
|
||||
|
||||
**Test ID**: TC018-48bit-large-fs
|
||||
**Category**: Filesystem Metadata
|
||||
**Priority**: Low
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a real FLAT_PLAIN read whose extended inode has `startblk_hi=1`, so the
|
||||
provider I/O occurs above 16 TiB rather than only reporting a large `statfs`
|
||||
total.
|
||||
|
||||
## Fixture Qualification
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc018.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
python3 tests/erofs_fixture.py inspect \
|
||||
"$work/fixtures/48bit-high-file-prefix.erofs" --path /high-offset.txt
|
||||
grep '^48bit-high-file-prefix ' "$work/fixtures/fixture-evidence.txt"
|
||||
sha256 -q "$work/fixtures/48bit-high-file-prefix.erofs"
|
||||
```
|
||||
|
||||
Require an extended nonempty FLAT_PLAIN inode, `startblk_hi=1`, a physical
|
||||
`data_offset >= 17592186044416`, a valid CRC, and an end offset within
|
||||
`required_provider_length`. The mutator zeros the original low-block payload,
|
||||
so a reader that ignores `startblk_hi` cannot return the expected source bytes.
|
||||
Read `required_provider_length`, `start_block`, `data_offset`,
|
||||
`low_decoy_offset`, and `file_size` from the evidence line.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
```sh
|
||||
provider="$work/48bit-high-file-provider.raw"
|
||||
cp "$work/fixtures/48bit-high-file-prefix.erofs" "$provider"
|
||||
truncate -s "$required_provider_length" "$provider"
|
||||
dd if="$work/fixtures/source/high-offset.txt" of="$provider" bs=4096 \
|
||||
seek="$start_block" conv=notrunc
|
||||
cc -O2 -Wall -Wextra -std=c17 tests/read_probe.c -o "$work/read_probe"
|
||||
"$work/read_probe" pread "$provider" "$low_decoy_offset" "$file_size" \
|
||||
"$work/raw-low-offset.txt"
|
||||
"$work/read_probe" pread "$provider" "$data_offset" "$file_size" \
|
||||
"$work/raw-high-offset.txt"
|
||||
dd if=/dev/zero of="$work/zero.bin" bs="$file_size" count=1
|
||||
cmp "$work/zero.bin" "$work/raw-low-offset.txt"
|
||||
! cmp -s "$work/fixtures/source/high-offset.txt" "$work/raw-low-offset.txt"
|
||||
cmp "$work/fixtures/source/high-offset.txt" "$work/raw-high-offset.txt"
|
||||
unit=$(mdconfig -a -t vnode -f "$provider")
|
||||
diskinfo -v "/dev/$unit"
|
||||
mkdir "$work/mnt"
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt"
|
||||
cmp "$work/fixtures/source/high-offset.txt" "$work/mnt/high-offset.txt"
|
||||
cmp "$work/fixtures/source/control.txt" "$work/mnt/control.txt"
|
||||
df -h "$work/mnt"
|
||||
umount "$work/mnt"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
rm -f "$provider"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
The raw provider probe and mounted file both return the exact source bytes from
|
||||
above 16 TiB, while a low-offset control remains valid. Record the prefix hash,
|
||||
sparse media size/allocation, high offset, source/data hash, dmesg delta, and
|
||||
cleanup. If sparse high-offset I/O is unavailable, mark SHELVED with all
|
||||
attempts; a large `df` result alone cannot pass TC018.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Test Case: Nonzero 48-bit Root NID
|
||||
|
||||
**Test ID**: TC019-48bit-root-nid
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the `48BIT && rootnid_8b != 0` selector uses the complete 64-bit root
|
||||
field and interprets the two-byte union as `blocks_hi`.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/root8-48bit.erofs`. The structured transformer requires incompat
|
||||
bit `0x80`, nonzero image-bounded `rootnid_8b`, `blocks_hi=0`, valid CRC32C,
|
||||
and unchanged provider-sized `blocks_lo`. Production fsck.erofs 1.8.6 does not
|
||||
recognize this feature; FreeBSD mount/read is mandatory.
|
||||
|
||||
## Procedure
|
||||
|
||||
Host field check:
|
||||
|
||||
```sh
|
||||
python3 tests/erofs_fixture.py inspect /work/build/repo22-g1/images/root8-48bit.erofs --path=/root.txt
|
||||
od -An -tu2 -j 1038 -N 2 /work/build/repo22-g1/images/root8-48bit.erofs
|
||||
od -An -tx4 -j 1104 -N 4 /work/build/repo22-g1/images/root8-48bit.erofs
|
||||
od -An -tu8 -j 1136 -N 8 /work/build/repo22-g1/images/root8-48bit.erofs
|
||||
```
|
||||
|
||||
Mount the same hashed image in FreeBSD, then run:
|
||||
|
||||
```sh
|
||||
stat -f 'root_ino=%i type=%HT' "$mnt"
|
||||
cmp /tmp/repo22-g1/source/compact/root.txt "$mnt/root.txt"
|
||||
sha256 /tmp/repo22-g1/source/compact/root.txt "$mnt/root.txt"
|
||||
./statfs_probe "$mnt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- `feature_incompat & 0x80` is set, `rootnid_8b` is nonzero, and observed root
|
||||
inode equals that complete field.
|
||||
- Root content matches the source and statfs uses `blocks_lo` plus zero
|
||||
`blocks_hi`; mount and cleanup succeed.
|
||||
- TC150's zero-`rootnid_8b` fallback is a separate selector and is not accepted
|
||||
as evidence for this TC.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Test Case: Compact Inode Decoding
|
||||
|
||||
**Test ID**: TC020-compact-inode-basic
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a real 32-byte compact regular inode exposes correct mode, link count,
|
||||
size, allocation, and source-exact data.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs` and `source/compact/small.txt`. The evidence records
|
||||
the NID and asserts `inode_size=32`.
|
||||
|
||||
## Procedure
|
||||
|
||||
After mounting on `$mnt`:
|
||||
|
||||
```sh
|
||||
stat -f 'ino=%i size=%z mode=%p nlink=%l blocks=%b mtime=%m' "$mnt/small.txt"
|
||||
wc -c /tmp/repo22-g1/source/compact/small.txt "$mnt/small.txt"
|
||||
cmp /tmp/repo22-g1/source/compact/small.txt "$mnt/small.txt"
|
||||
sha256 /tmp/repo22-g1/source/compact/small.txt "$mnt/small.txt"
|
||||
```
|
||||
|
||||
Unmount and detach the exact md unit.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- The inode is compact, regular mode `0644`, link count 1, timestamp 0, and
|
||||
size equal to the source.
|
||||
- Full content and hashes match; all operations and cleanup return zero.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: Compact Inode I_NLINK_1
|
||||
|
||||
**Test ID**: TC021-compact-inode-nlink1
|
||||
|
||||
## Objective
|
||||
|
||||
Verify bit 4 on a non-directory compact inode forces `st_nlink=1` while the
|
||||
`i_nb` union remains available for address high bits.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact-nlink1.erofs` and `source/compact/single.txt`.
|
||||
`fixture-evidence.txt` asserts a 32-byte regular inode, bit 4 set,
|
||||
`i_nb=0x1234`, and valid recomputed CRC32C.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'ino=%i nlink=%l size=%z mode=%p' "$mnt/single.txt"
|
||||
cmp /tmp/repo22-g1/source/compact/single.txt "$mnt/single.txt"
|
||||
sha256 /tmp/repo22-g1/source/compact/single.txt "$mnt/single.txt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- `st_nlink=1` despite on-disk `i_nb=0x1234`.
|
||||
- Inline file data remains source-exact; mount and cleanup succeed.
|
||||
- An `i_nb` value of zero is not used as a substitute for the bit-4 encoding.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Test Case: Compact Special Inodes and Linux dev_t Decode
|
||||
|
||||
**Test ID**: TC022-compact-inode-special
|
||||
|
||||
## Objective
|
||||
|
||||
Verify compact char/block/FIFO inodes and Linux `new_decode_dev` conversion to
|
||||
FreeBSD `dev_t`.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs`. Source metadata records real nodes
|
||||
`char-large=2748:344865`, `block-large=2748:344865`, and `fifo`; structured
|
||||
evidence asserts compact inodes and raw on-disk `i_u.rdev=0x543abc21` for both
|
||||
devices. Compile `tests/stat_special.c` natively in FreeBSD.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
./stat_special char "$mnt/char-large" 2748 344865
|
||||
./stat_special block "$mnt/block-large" 2748 344865
|
||||
./stat_special fifo "$mnt/fifo"
|
||||
stat -f '%N mode=%p rdev=%r' "$mnt/char-large" "$mnt/block-large" "$mnt/fifo"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Char and block helpers report major 2748, minor 344865, and raw FreeBSD
|
||||
`st_rdev=0xa430005bc21`.
|
||||
- FIFO type is correct and `st_rdev=NODEV`.
|
||||
- A raw little-endian cast would differ; all helper checks and cleanup pass.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Test Case: Extended Inode Decoding
|
||||
|
||||
**Test ID**: TC023-extended-inode-normal
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a real 64-byte extended regular inode, including size, full-width
|
||||
metadata, timestamps, and source-exact content.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/extended.erofs` and `source/extended/large-file.bin`.
|
||||
`fixture-evidence.txt` records the NID, byte offset, size, and `inode_size=64`.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'ino=%i size=%z mode=%p nlink=%l mtime=%m ctime=%c blocks=%b' "$mnt/large-file.bin"
|
||||
cmp /tmp/repo22-g1/source/extended/large-file.bin "$mnt/large-file.bin"
|
||||
sha256 /tmp/repo22-g1/source/extended/large-file.bin "$mnt/large-file.bin"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- The file reports the evidence/source size, regular `0644`, link count 1,
|
||||
deterministic timestamps, and a 64-byte on-disk inode.
|
||||
- Full source compare and SHA256 match; cleanup succeeds.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Test Case: Extended Inode File Above 4 GiB
|
||||
|
||||
**Test ID**: TC024-extended-inode-large
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a 64-bit extended `i_size` above 4 GiB without materializing a multi-GiB
|
||||
payload, using deterministic FLAT_PLAIN hole reads at distant offsets.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/extended-large-hole.erofs` and
|
||||
`expected/large-hole-zero-64k.bin`. Structured evidence asserts a 64-byte
|
||||
inode, size `4294971393`, layout 0, `startblk=0xffffffffffff`, valid CRC, and
|
||||
an all-zero content descriptor.
|
||||
|
||||
## Procedure
|
||||
|
||||
After mounting, run three bounded reads:
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b mode=%p' "$mnt/huge-sparse.dat"
|
||||
./read_probe pread "$mnt/huge-sparse.dat" 0 65536 /tmp/tc024-start
|
||||
./read_probe pread "$mnt/huge-sparse.dat" 2147483648 65536 /tmp/tc024-middle
|
||||
./read_probe pread "$mnt/huge-sparse.dat" 4294905857 65536 /tmp/tc024-end
|
||||
cmp /tmp/repo22-g1/expected/large-hole-zero-64k.bin /tmp/tc024-start
|
||||
cmp /tmp/repo22-g1/expected/large-hole-zero-64k.bin /tmp/tc024-middle
|
||||
cmp /tmp/repo22-g1/expected/large-hole-zero-64k.bin /tmp/tc024-end
|
||||
sha256 /tmp/tc024-start /tmp/tc024-middle /tmp/tc024-end
|
||||
```
|
||||
|
||||
Remove outputs, unmount, and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Size is exactly `4294971393`, not truncated to 32 bits.
|
||||
- Start, middle, and final 64 KiB ranges match the deterministic zero source.
|
||||
- Reads are bounded, no large allocation/panic occurs, and cleanup succeeds.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Test Case: Compact Inode Link-Count Rules
|
||||
|
||||
**Test ID**: TC025-nlink1-handling
|
||||
|
||||
## Objective
|
||||
|
||||
Compare explicit compact link counts, bit-4 single-link encoding, hard links,
|
||||
and directory link counts without conflating directory dot omission.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs` and `images/compact-nlink1.erofs`. Evidence asserts
|
||||
explicit `single.txt i_nb=1`, patched bit 4 plus `i_nb=0x1234`, identical
|
||||
hard-link NID with `i_nb=2`, and explicit directory nlink.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount each image separately and record:
|
||||
|
||||
```sh
|
||||
stat -f '%N ino=%i nlink=%l mode=%p' \
|
||||
"$mnt/single.txt" "$mnt/hard-a.txt" "$mnt/hard-b.txt" "$mnt/dotdir"
|
||||
cmp /tmp/repo22-g1/source/compact/single.txt "$mnt/single.txt"
|
||||
cmp /tmp/repo22-g1/source/compact/hard-a.txt "$mnt/hard-a.txt"
|
||||
cmp "$mnt/hard-a.txt" "$mnt/hard-b.txt"
|
||||
```
|
||||
|
||||
Unmount and detach before attaching the second image.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Baseline and patched `single.txt` both report nlink 1 for different valid
|
||||
encodings.
|
||||
- `hard-a.txt` and `hard-b.txt` share one inode and report nlink 2.
|
||||
- `dotdir` uses its explicit directory link count; all data compares pass.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test Case: Directory with dot_omitted
|
||||
|
||||
**Test ID**: TC026-dot-omitted-with
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a bit-4 directory omits only `.` on disk, retains explicit `..`, and
|
||||
receives a synthetic `.` from FreeBSD readdir.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact-dot-omitted.erofs`. Structured evidence records bit 4,
|
||||
on-disk names `..,child.txt`, 48-bit incompat selection with nonzero
|
||||
`rootnid_8b`, `blocks_hi=0`, and valid CRC. Production fsck.erofs 1.8.6 cannot
|
||||
qualify this newer format.
|
||||
|
||||
## Procedure
|
||||
|
||||
After mounting in FreeBSD:
|
||||
|
||||
```sh
|
||||
stat -f 'ino=%i nlink=%l mode=%p' "$mnt/dotdir"
|
||||
ls -lai "$mnt/dotdir"
|
||||
(cd "$mnt/dotdir" && test "$(pwd)" = "$mnt/dotdir")
|
||||
cmp /tmp/repo22-g1/source/compact/dotdir/child.txt "$mnt/dotdir/child.txt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- User-visible listing contains both `.` and `..`; `.` has the directory NID.
|
||||
- Structured evidence, not the listing, proves `.` is absent on disk and bit 4
|
||||
is set; `..` remains an on-disk entry.
|
||||
- Child data, navigation, mount, and cleanup succeed.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Test Case: Directory without dot_omitted
|
||||
|
||||
**Test ID**: TC027-dot-omitted-without
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a bit-4-clear directory reads explicit on-disk `.` and `..` entries.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/compact.erofs` and `/dotdir`. Structured evidence asserts bit 4 is
|
||||
clear and names are `.,..,child.txt`; production `dump.erofs --ls` also
|
||||
qualifies this baseline.
|
||||
|
||||
## Procedure
|
||||
|
||||
Host:
|
||||
|
||||
```sh
|
||||
dump.erofs --ls --path=/dotdir /work/build/repo22-g1/images/compact.erofs
|
||||
```
|
||||
|
||||
Guest after mount:
|
||||
|
||||
```sh
|
||||
stat -f 'ino=%i nlink=%l mode=%p' "$mnt/dotdir"
|
||||
ls -lai "$mnt/dotdir"
|
||||
cmp /tmp/repo22-g1/source/compact/dotdir/child.txt "$mnt/dotdir/child.txt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Host inspection and FreeBSD listing both contain explicit `.` and `..`.
|
||||
- Child data matches the source, directory attributes are valid, and cleanup
|
||||
succeeds.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Test Case: FLAT_PLAIN Small File
|
||||
|
||||
**Test ID**: TC028-flat-plain-small
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a sub-block regular file explicitly encoded as uncompressed
|
||||
`FLAT_PLAIN` reads source-exactly.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs` and `source/flat/small.txt`. Structured evidence asserts
|
||||
layout 0 and records NID and size.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b mode=%p' "$mnt/small.txt"
|
||||
cmp /tmp/repo22-g1/source/flat/small.txt "$mnt/small.txt"
|
||||
sha256 /tmp/repo22-g1/source/flat/small.txt "$mnt/small.txt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Evidence proves `FLAT_PLAIN`; size and data match the source.
|
||||
- The read, hash, mount, and cleanup all succeed.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: FLAT_PLAIN Medium File
|
||||
|
||||
**Test ID**: TC029-flat-plain-medium
|
||||
|
||||
## Objective
|
||||
|
||||
Verify complete and nonzero-offset reads of a multi-block `FLAT_PLAIN` file.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs`, `source/flat/medium.dat`, and
|
||||
`expected/medium-10-5.bin`. Evidence asserts layout 0 and size 102417.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b' "$mnt/medium.dat"
|
||||
cmp /tmp/repo22-g1/source/flat/medium.dat "$mnt/medium.dat"
|
||||
./read_probe pread "$mnt/medium.dat" 40960 20480 /tmp/tc029-range
|
||||
cmp /tmp/repo22-g1/expected/medium-10-5.bin /tmp/tc029-range
|
||||
sha256 /tmp/repo22-g1/source/flat/medium.dat "$mnt/medium.dat" \
|
||||
/tmp/repo22-g1/expected/medium-10-5.bin /tmp/tc029-range
|
||||
```
|
||||
|
||||
Remove the range output, unmount, and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Full file and the five-block range match their deterministic sources.
|
||||
- No block-boundary truncation or cleanup failure occurs.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test Case: FLAT_PLAIN Large File
|
||||
|
||||
**Test ID**: TC030-flat-plain-large
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a greater-than-10-MiB contiguous `FLAT_PLAIN` file across thousands of
|
||||
filesystem blocks.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs` and `source/flat/large.bin`. Evidence asserts layout 0
|
||||
and size 10485791.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b' "$mnt/large.bin"
|
||||
dd if="$mnt/large.bin" of=/tmp/tc030-full bs=1m
|
||||
cmp /tmp/repo22-g1/source/flat/large.bin /tmp/tc030-full
|
||||
sha256 /tmp/repo22-g1/source/flat/large.bin /tmp/tc030-full
|
||||
./read_probe pread "$mnt/large.bin" 5242880 1048576 /tmp/tc030-seek
|
||||
dd if=/tmp/repo22-g1/source/flat/large.bin of=/tmp/tc030-source-seek \
|
||||
bs=1m skip=5 count=1
|
||||
cmp /tmp/tc030-source-seek /tmp/tc030-seek
|
||||
```
|
||||
|
||||
Remove all outputs, unmount, and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Reported size is exact; full and seeked data match the source.
|
||||
- No mapping error, panic, or cleanup failure occurs.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: FLAT_INLINE Small File
|
||||
|
||||
**Test ID**: TC031-flat-inline-normal
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a small uncompressed `FLAT_INLINE` payload stored in the inode metadata
|
||||
area and bounded by its metadata block.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/inline.erofs` and `source/inline/tiny.txt`. Evidence asserts layout
|
||||
2, compact inode, NID, and size.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b mode=%p' "$mnt/tiny.txt"
|
||||
cmp /tmp/repo22-g1/source/inline/tiny.txt "$mnt/tiny.txt"
|
||||
sha256 /tmp/repo22-g1/source/inline/tiny.txt "$mnt/tiny.txt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Layout is 2 and size/content match the source.
|
||||
- FreeBSD reports 8 allocated 512-byte sectors for the 4096-byte EROFS
|
||||
allocation unit; zero blocks is not the current qualified semantic.
|
||||
- Mount and cleanup succeed.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Test Case: FLAT_INLINE Zero-Length File
|
||||
|
||||
**Test ID**: TC032-flat-inline-zero
|
||||
|
||||
## Objective
|
||||
|
||||
Verify an explicitly layout-2 zero-length compact inode returns clean EOF and
|
||||
zero allocation.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/inline-zero.erofs` and `source/inline/empty.txt`. The transformer
|
||||
asserts compact `FLAT_INLINE`, size 0, valid CRC, and records the image/source
|
||||
hashes.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b mode=%p' "$mnt/empty.txt"
|
||||
cmp /tmp/repo22-g1/source/inline/empty.txt "$mnt/empty.txt"
|
||||
test "$(wc -c < "$mnt/empty.txt")" -eq 0
|
||||
sha256 /tmp/repo22-g1/source/inline/empty.txt "$mnt/empty.txt"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Size and byte count are zero, `st_blocks=0`, hashes match the empty source,
|
||||
and no read error occurs.
|
||||
- Mount and cleanup succeed.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test Case: FLAT_INLINE Tailpacking
|
||||
|
||||
**Test ID**: TC033-tailpacking-normal
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a 5000-byte file reads exactly across its full data block and 904-byte
|
||||
inline tail boundary.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/inline.erofs` and `source/inline/tailpacked.dat`. Evidence asserts
|
||||
layout 2 and size 5000.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b' "$mnt/tailpacked.dat"
|
||||
cmp /tmp/repo22-g1/source/inline/tailpacked.dat "$mnt/tailpacked.dat"
|
||||
sha256 /tmp/repo22-g1/source/inline/tailpacked.dat "$mnt/tailpacked.dat"
|
||||
./read_probe pread "$mnt/tailpacked.dat" 4080 64 /tmp/tc033-mounted-range
|
||||
dd if=/tmp/repo22-g1/source/inline/tailpacked.dat \
|
||||
of=/tmp/tc033-source-range bs=1 skip=4080 count=64 2>/dev/null
|
||||
cmp /tmp/tc033-source-range /tmp/tc033-mounted-range
|
||||
```
|
||||
|
||||
Remove outputs, unmount, and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Full file and the range crossing logical offset 4096 match the source.
|
||||
- The transition from plain block data to metadata tail is seamless and
|
||||
cleanup succeeds.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Test Case: Tailpacking Block Boundaries
|
||||
|
||||
**Test ID**: TC034-tailpacking-boundary
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the actual erofs-utils boundary choices at 4095, 4096, and 4097 bytes,
|
||||
including the one-byte inline tail case.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/inline.erofs` and the three matching files under `source/inline`.
|
||||
Structured evidence requires layouts `0,0,2` respectively. A 4095-byte payload
|
||||
cannot fit beside a 32-byte inode in one 4096-byte metadata block, so it is not
|
||||
claimed as fully inline.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
for size in 4095 4096 4097; do
|
||||
stat -f '%N size=%z blocks=%b' "$mnt/file-$size.dat"
|
||||
cmp "/tmp/repo22-g1/source/inline/file-$size.dat" "$mnt/file-$size.dat"
|
||||
sha256 "/tmp/repo22-g1/source/inline/file-$size.dat" "$mnt/file-$size.dat"
|
||||
done
|
||||
./read_probe pread "$mnt/file-4097.dat" 4088 9 /tmp/tc034-boundary
|
||||
dd if=/tmp/repo22-g1/source/inline/file-4097.dat \
|
||||
of=/tmp/tc034-source bs=1 skip=4088 count=9 2>/dev/null
|
||||
cmp /tmp/tc034-source /tmp/tc034-boundary
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Exact sizes and full hashes match for all three files.
|
||||
- 4095 and 4096 are FLAT_PLAIN; 4097 is FLAT_INLINE with a one-byte tail.
|
||||
- The nine-byte cross-boundary range matches; cleanup succeeds.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Test Case: Sequential Regular-File Read
|
||||
|
||||
**Test ID**: TC035-file-read-sequential
|
||||
|
||||
## Objective
|
||||
|
||||
Verify buffered sequential reads return every byte of a deterministic
|
||||
multi-block regular file.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs` and `source/flat/data.txt`. Evidence asserts
|
||||
`FLAT_PLAIN`, NID, and size 262163.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b' "$mnt/data.txt"
|
||||
dd if="$mnt/data.txt" of=/tmp/tc035.out bs=4096
|
||||
cmp /tmp/repo22-g1/source/flat/data.txt /tmp/tc035.out
|
||||
sha256 /tmp/repo22-g1/source/flat/data.txt /tmp/tc035.out
|
||||
```
|
||||
|
||||
Remove output, unmount, and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- `dd` reaches exact EOF and the complete output matches the source/hash.
|
||||
- No short read, data corruption, dmesg error, or cleanup failure occurs.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Random Regular-File Reads
|
||||
|
||||
**Test ID**: TC036-file-read-random
|
||||
|
||||
## Objective
|
||||
|
||||
Verify independent start, middle, and end `pread(2)` ranges from a deterministic
|
||||
1 MiB regular file.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs`, `source/flat/random-test.bin`, and the three
|
||||
`expected/random-*.bin` files. Evidence asserts layout 0 and exact size.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
./read_probe pread "$mnt/random-test.bin" 0 10240 /tmp/tc036-start
|
||||
./read_probe pread "$mnt/random-test.bin" 512000 10240 /tmp/tc036-mid
|
||||
./read_probe pread "$mnt/random-test.bin" 1024000 24576 /tmp/tc036-end
|
||||
cmp /tmp/repo22-g1/expected/random-start.bin /tmp/tc036-start
|
||||
cmp /tmp/repo22-g1/expected/random-mid.bin /tmp/tc036-mid
|
||||
cmp /tmp/repo22-g1/expected/random-end.bin /tmp/tc036-end
|
||||
sha256 /tmp/tc036-start /tmp/tc036-mid /tmp/tc036-end
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Every bounded `pread` reports its requested byte count and exact offset.
|
||||
- All three ranges match independently generated source ranges; cleanup passes.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test Case: Large Regular-File Read
|
||||
|
||||
**Test ID**: TC037-file-read-large
|
||||
|
||||
## Objective
|
||||
|
||||
Verify complete and distant-range reads of a deterministic file larger than
|
||||
100 MiB without a correctness shortcut based only on throughput.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs`, `source/flat/huge-data.bin`, and
|
||||
`expected/huge-sample.bin`. Evidence asserts layout 0 and size 104857857.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
stat -f 'size=%z blocks=%b' "$mnt/huge-data.bin"
|
||||
time dd if="$mnt/huge-data.bin" of=/tmp/tc037-full bs=1m
|
||||
cmp /tmp/repo22-g1/source/flat/huge-data.bin /tmp/tc037-full
|
||||
sha256 /tmp/repo22-g1/source/flat/huge-data.bin /tmp/tc037-full
|
||||
./read_probe pread "$mnt/huge-data.bin" 52428800 5242880 /tmp/tc037-sample
|
||||
cmp /tmp/repo22-g1/expected/huge-sample.bin /tmp/tc037-sample
|
||||
sha256 /tmp/repo22-g1/expected/huge-sample.bin /tmp/tc037-sample
|
||||
```
|
||||
|
||||
Remove outputs, unmount, and detach.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Exact size, full compare, and 50 MiB-offset sample compare all pass.
|
||||
- Record elapsed time but impose no host-dependent QEMU throughput threshold.
|
||||
- No memory exhaustion, panic, or cleanup failure occurs.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Short Symlink Target
|
||||
|
||||
**Test ID**: TC038-symlink-short
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a short `FLAT_INLINE` symlink returns the exact source target and follows
|
||||
to source-exact file data.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/inline.erofs`, `source/inline/link1`, and
|
||||
`source/inline/target.txt`. Evidence asserts symlink mode, layout 2, and target
|
||||
length 10.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
test -L "$mnt/link1"
|
||||
readlink /tmp/repo22-g1/source/inline/link1 > /tmp/tc038-source-target
|
||||
readlink "$mnt/link1" > /tmp/tc038-mount-target
|
||||
cmp /tmp/tc038-source-target /tmp/tc038-mount-target
|
||||
cmp /tmp/repo22-g1/source/inline/target.txt "$mnt/link1"
|
||||
sha256 /tmp/repo22-g1/source/inline/target.txt "$mnt/link1"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- `readlink` returns exactly `target.txt`, without newline truncation ambiguity.
|
||||
- Following the link yields the exact target source; cleanup succeeds.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Test Case: Long Symlink Target
|
||||
|
||||
**Test ID**: TC039-symlink-long
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a greater-than-60-byte EROFS symlink target is returned completely and
|
||||
follows correctly.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/flat.erofs`, `source/flat/longlink`, and its nested target file.
|
||||
Structured evidence records symlink size 73 and actual layout 2. EROFS does not
|
||||
switch to a separate-data-block symlink merely at 60 bytes; that former fixture
|
||||
assumption is invalid.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
test -L "$mnt/longlink"
|
||||
readlink /tmp/repo22-g1/source/flat/longlink > /tmp/tc039-source-target
|
||||
readlink "$mnt/longlink" > /tmp/tc039-mount-target
|
||||
cmp /tmp/tc039-source-target /tmp/tc039-mount-target
|
||||
test "$(wc -c < /tmp/tc039-mount-target)" -eq 74
|
||||
cmp /tmp/repo22-g1/source/flat/very/long/path/to/a/deeply/nested/deterministic/target/directory/file.txt \
|
||||
"$mnt/longlink"
|
||||
sha256 "$mnt/longlink" \
|
||||
/tmp/repo22-g1/source/flat/very/long/path/to/a/deeply/nested/deterministic/target/directory/file.txt
|
||||
```
|
||||
|
||||
The `wc` count is 73 target bytes plus the output newline.
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Source and mounted targets match exactly and exceed 60 bytes.
|
||||
- The link follows to source-exact data with no truncation; cleanup succeeds.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Broken Symlink
|
||||
|
||||
**Test ID**: TC040-symlink-broken
|
||||
|
||||
## Objective
|
||||
|
||||
Verify `readlink(2)` succeeds for a deterministic broken link while following
|
||||
the target fails with exact `ENOENT`.
|
||||
|
||||
## Fixture
|
||||
|
||||
Use `images/inline.erofs` and `source/inline/brokenlink`. Evidence asserts
|
||||
symlink mode, layout 2, and target length 29.
|
||||
|
||||
## Procedure
|
||||
|
||||
```sh
|
||||
test -L "$mnt/brokenlink"
|
||||
readlink /tmp/repo22-g1/source/inline/brokenlink > /tmp/tc040-source-target
|
||||
readlink "$mnt/brokenlink" > /tmp/tc040-mount-target
|
||||
cmp /tmp/tc040-source-target /tmp/tc040-mount-target
|
||||
./read_probe expect-error "$mnt/brokenlink" 2
|
||||
./read_probe expect-error "$mnt/brokenlink" 2
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
- Both `readlink` targets equal `/nonexistent/repo22-g1-target`.
|
||||
- Both follow attempts return errno 2 (`ENOENT`), while the symlink itself
|
||||
remains visible; no kernel error or cleanup failure occurs.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Test Case: Directory Entry Decoding - Normal
|
||||
|
||||
**Test ID**: TC041-dirent-decode-normal
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Decode every entry type and the 255-byte filename from the deterministic VFS
|
||||
fixture through FreeBSD getdirentries(2), not inferred ls formatting.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs using G3-MANUAL-SETUP.md, then run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/testdir 512
|
||||
find /tmp/repo22-g3/mnt/testdir -maxdepth 1 -print |
|
||||
sed 's#.*/##' | sort > actual-testdir.txt
|
||||
cmp fixtures/vfs/expected-testdir.txt actual-testdir.txt
|
||||
name=$(find /tmp/repo22-g3/mnt/testdir -maxdepth 1 -type f \
|
||||
-name 'long-*')
|
||||
test "$(basename "$name" | tr -d '\n' | wc -c)" -eq 255
|
||||
|
||||
## Expected Results
|
||||
|
||||
The probe reports 36 unique entries, correct DT_DIR/DT_REG/DT_LNK counts,
|
||||
strictly increasing restartable cookies, and one deterministic name/type hash.
|
||||
The 34 real names match the manifest exactly and the longest name is 255 bytes.
|
||||
Record probe output, manifest/image hashes, and mount/md cleanup.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: Directory Entry Decoding - Multi-Block Directory
|
||||
|
||||
**Test ID**: TC042-dirent-large-dir
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Decode a real multi-block directory without missing, duplicating, or
|
||||
truncating entries across directory-block boundaries.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount metadata/namei-base.erofs and run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/wide 128
|
||||
find /tmp/repo22-g3/mnt/wide -maxdepth 1 -type f |
|
||||
sed 's#.*/##' | sort > actual-wide.txt
|
||||
cmp fixtures/metadata/expected-wide.txt actual-wide.txt
|
||||
stat /tmp/repo22-g3/mnt/wide/entry-000-abcdefghijklmnopqrstuvwxyz.txt
|
||||
stat /tmp/repo22-g3/mnt/wide/entry-159-abcdefghijklmnopqrstuvwxyz.txt
|
||||
stat /tmp/repo22-g3/mnt/wide/entry-319-abcdefghijklmnopqrstuvwxyz.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
All 320 real files plus dot and dotdot are returned once. The helper reports
|
||||
322 restartable kernel and libc positions and the three boundary samples stat
|
||||
successfully. Record the image hash and cleanup.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Test Case: Lookup - Existing Entries
|
||||
|
||||
**Test ID**: TC043-lookup-found
|
||||
**Category**: Directory Operations
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify exact-name lookup of regular, directory, and symlink entries returns
|
||||
stable vnode metadata and source-exact data.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/file.txt
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/subdir
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/shortlink
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/file.txt
|
||||
cmp fixtures/vfs/source/testdir/file.txt \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt
|
||||
sha256 fixtures/vfs/source/testdir/file.txt \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
All lookups succeed, repeated file lookup reports the same nonzero inode, each
|
||||
type/mode/size matches fixture evidence, and source/mounted hashes are equal.
|
||||
Record command statuses and cleanup.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: Lookup - Missing Entry
|
||||
|
||||
**Test ID**: TC044-lookup-not-found
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify direct missing lookups return exact ENOENT without masking existing
|
||||
entries or turning other errors into a miss.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/testdir/nonexistent.txt 2
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/testdir/nonexistent.txt 2
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/no-such-directory/file.txt 2
|
||||
./g3_vfs_probe expect-success stat \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
Each missing syscall reports errno 2 and the positive control succeeds.
|
||||
Wrapper text alone is not evidence; record the helper output and cleanup.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Test Case: Lookup - Case Sensitivity
|
||||
|
||||
**Test ID**: TC045-lookup-case-sensitive
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify four distinct case variants resolve independently and an unrecorded
|
||||
case variant returns ENOENT.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
stat -f 'name=%N ino=%i size=%z' \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt \
|
||||
/tmp/repo22-g3/mnt/testdir/File.txt \
|
||||
/tmp/repo22-g3/mnt/testdir/FILE.TXT \
|
||||
/tmp/repo22-g3/mnt/testdir/FiLe.TxT
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/testdir/fILE.txt 2
|
||||
|
||||
## Expected Results
|
||||
|
||||
The four exact variants have four nonzero, distinct NIDs and their recorded
|
||||
sizes. The unmatched spelling returns errno 2. Record output and cleanup.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: Readdir - Basic Completeness
|
||||
|
||||
**Test ID**: TC046-readdir-basic
|
||||
**Category**: Directory Operations
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify one complete getdirentries(2)/readdir(3) traversal returns the exact
|
||||
fixture set, including dot and dotdot.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/testdir 4096
|
||||
find /tmp/repo22-g3/mnt/testdir -maxdepth 1 -mindepth 1 -print |
|
||||
sed 's#.*/##' | sort > actual-testdir.txt
|
||||
cmp fixtures/vfs/expected-testdir.txt actual-testdir.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
The manifest comparison is exact; the probe reports 36 unique entries and the
|
||||
same ordered name/type hash through both APIs. Record the image hash and
|
||||
cleanup.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: Readdir - Multi-Block Completeness
|
||||
|
||||
**Test ID**: TC047-readdir-large
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify repeated small-buffer reads cover a 320-file multi-block directory
|
||||
exactly once.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount metadata/namei-base.erofs and run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/wide 128
|
||||
find /tmp/repo22-g3/mnt/wide -maxdepth 1 -type f |
|
||||
sed 's#.*/##' | sort > actual-wide.txt
|
||||
test "$(wc -l < actual-wide.txt)" -eq 320
|
||||
test "$(sort actual-wide.txt | uniq -d | wc -l)" -eq 0
|
||||
|
||||
Compare actual-wide.txt with fixtures/metadata/expected-wide.txt.
|
||||
|
||||
## Expected Results
|
||||
|
||||
The helper reports 322 unique entries and 322 valid restart positions with a
|
||||
128-byte userspace buffer; the exact manifest has 320 names and no duplicates.
|
||||
Record the probe hash and cleanup.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Test Case: Readdir Cookies and seekdir Resume
|
||||
|
||||
**Test ID**: TC048-readdir-seek
|
||||
**Category**: Directory Operations
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify every kernel d_off and libc telldir cookie resumes at the next exact
|
||||
entry; complete second traversals are not substitutes.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount metadata/namei-base.erofs and run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/wide 128 |
|
||||
tee TC048-probe.out
|
||||
|
||||
## Probe Contract
|
||||
|
||||
The helper fails on non-increasing cookies, invalid records, duplicate names,
|
||||
kernel/libc order or type differences, a restart at the wrong next name, or a
|
||||
final cookie that does not reach EOF. Kernel d_off values are validated after
|
||||
reopen/lseek; each libc telldir value is passed back to seekdir on the same
|
||||
DIR stream that produced it, as required by the API contract.
|
||||
|
||||
## Expected Results
|
||||
|
||||
The helper exits zero and reports entries=322, d_off_restarts=322,
|
||||
seekdir_restarts=322, buffer=128, the type counts, and one FNV-1a name/type
|
||||
hash. Record literal output and cleanup.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Test Case: Dot Entry Handling
|
||||
|
||||
**Test ID**: TC049-dot-handling
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify dot is returned as a directory entry and explicit dot lookup resolves
|
||||
to the same vnode as its directory.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/testdir 128
|
||||
stat -f '%i %HT' /tmp/repo22-g3/mnt/testdir
|
||||
stat -f '%i %HT' /tmp/repo22-g3/mnt/testdir/.
|
||||
cmp fixtures/vfs/source/testdir/file.txt \
|
||||
/tmp/repo22-g3/mnt/./testdir/./file.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
The traversal includes one dot entry with DT_DIR, both stat commands report
|
||||
the same directory NID, and paths containing dot read source-exact data.
|
||||
Record output and cleanup.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Test Case: Dotdot Entry Handling
|
||||
|
||||
**Test ID**: TC050-dotdot-handling
|
||||
**Category**: Directory Operations
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify dotdot is returned and resolves nested paths to the correct parent
|
||||
vnode without lock-order failure.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./readdir_probe /tmp/repo22-g3/mnt/parent/child 128
|
||||
stat -f '%i %HT' /tmp/repo22-g3/mnt/parent
|
||||
stat -f '%i %HT' /tmp/repo22-g3/mnt/parent/child/..
|
||||
cmp fixtures/vfs/source/parent/file.txt \
|
||||
/tmp/repo22-g3/mnt/parent/child/grandchild/../../file.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
The traversal contains one dotdot DT_DIR entry, both parent stat commands
|
||||
report the same NID, and multiple dotdot components reach the expected file.
|
||||
Record output, dmesg delta, and cleanup.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Test Case: Repeated Positive Lookup Behavior
|
||||
|
||||
**Test ID**: TC051-namecache-hit
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify repeated positive pathname lookups remain stable within one mount.
|
||||
This is behavior-level namecache integration coverage; timing differences do
|
||||
not prove an internal cache hit.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
stat -f 'ino=%i mode=%p size=%z gen=%v' \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt > TC051-first.txt
|
||||
stat -f 'ino=%i mode=%p size=%z gen=%v' \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt > TC051-second.txt
|
||||
cmp TC051-first.txt TC051-second.txt
|
||||
cmp fixtures/vfs/source/testdir/file.txt \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
Both lookups succeed with byte-identical metadata and data. Record only this
|
||||
observable behavior as PASS; do not claim a measured cache hit without kernel
|
||||
instrumentation. Record output and cleanup.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: Repeated Negative Lookup Behavior
|
||||
|
||||
**Test ID**: TC052-namecache-miss
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify repeated missing-name lookups consistently return ENOENT and do not
|
||||
poison a later positive lookup. This is behavior-level negative-namecache
|
||||
coverage, not proof of an internal cache hit.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/testdir/cache-missing 2
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/testdir/cache-missing 2
|
||||
./g3_vfs_probe expect-success stat \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
Both negative syscalls report errno 2 and the positive control succeeds.
|
||||
Record the stable behavior honestly, with no latency-based cache assertion,
|
||||
then clean the mount and md.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Stable Vnode Identity Behavior
|
||||
|
||||
**Test ID**: TC053-vfs-hash-integration
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify repeated resolutions of one EROFS NID expose one stable vnode identity
|
||||
and file handle within a mount. This is behavior-level coverage of the
|
||||
vfs_hash contract; it does not directly observe the internal hash bucket.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
stat -f 'ino=%i gen=%v size=%z' \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt > TC053-a.txt
|
||||
stat -f 'ino=%i gen=%v size=%z' \
|
||||
/tmp/repo22-g3/mnt/testdir/./file.txt > TC053-b.txt
|
||||
cmp TC053-a.txt TC053-b.txt
|
||||
./nfs_fh_tool capture /tmp/repo22-g3/mnt/testdir/file.txt TC053-a.fh
|
||||
./nfs_fh_tool capture /tmp/repo22-g3/mnt/testdir/./file.txt TC053-b.fh
|
||||
./nfs_fh_tool compare TC053-a.fh TC053-b.fh
|
||||
./nfs_fh_tool describe TC053-a.fh
|
||||
|
||||
## Expected Results
|
||||
|
||||
Metadata and handles are identical and the handle NID/generation matches stat.
|
||||
Record this observable identity behavior, handle hash, and cleanup.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Parent Vnode Lookup Behavior
|
||||
|
||||
**Test ID**: TC054-vn-vget-ino
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify repeated dotdot lookups return the correct stable parent vnode without
|
||||
deadlock. This is behavior-level coverage of the vn_vget_ino path; userspace
|
||||
cannot prove the internal helper call by timing.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
stat -f 'ino=%i gen=%v type=%HT' \
|
||||
/tmp/repo22-g3/mnt/parent > TC054-parent.txt
|
||||
stat -f 'ino=%i gen=%v type=%HT' \
|
||||
/tmp/repo22-g3/mnt/parent/child/.. > TC054-dotdot1.txt
|
||||
stat -f 'ino=%i gen=%v type=%HT' \
|
||||
/tmp/repo22-g3/mnt/parent/child/.. > TC054-dotdot2.txt
|
||||
cmp TC054-parent.txt TC054-dotdot1.txt
|
||||
cmp TC054-dotdot1.txt TC054-dotdot2.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
All commands complete, metadata is identical, and dmesg has no lock-order,
|
||||
trap, or panic report. Record behavior and cleanup without claiming direct
|
||||
internal instrumentation.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: getattr Basic Metadata
|
||||
|
||||
**Test ID**: TC055-getattr-basic
|
||||
**Category**: Vnode Operations
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify VOP_GETATTR returns fixture-exact type, mode, ownership, link count,
|
||||
size, allocation, block size, inode, and generation for plain and compressed
|
||||
regular files.
|
||||
|
||||
## Procedure
|
||||
|
||||
On separate fresh mounts of vfs/vfs-plain.erofs and vfs/vfs-lz4.erofs:
|
||||
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/pager.bin
|
||||
stat -f 'ino=%i mode=%p uid=%u gid=%g nlink=%l size=%z blocks=%b blksize=%k gen=%v type=%HT' \
|
||||
/tmp/repo22-g3/mnt/pager.bin
|
||||
sha256 /tmp/repo22-g3/mnt/pager.bin
|
||||
|
||||
For the plain mount also compare the mounted hash with
|
||||
fixtures/vfs/source/pager.bin and fixture evidence.
|
||||
|
||||
## Expected Results
|
||||
|
||||
Both files are regular mode 0644, uid/gid 0, size 21211, block size 4096, with
|
||||
nonzero stable NID/generation. Both logical hashes equal the source hash;
|
||||
st_blocks records each inode's reported allocated sectors. Record both image
|
||||
hashes and per-mount cleanup.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: getattr Special Files
|
||||
|
||||
**Test ID**: TC056-getattr-special
|
||||
**Category**: Vnode Operations
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify compact and extended char, block, and FIFO inodes expose exact types,
|
||||
device numbers, zero size/allocation, and stable generation.
|
||||
|
||||
## Procedure
|
||||
|
||||
On fresh mounts of metadata/special-compact.erofs and
|
||||
metadata/special-extended.erofs:
|
||||
|
||||
./stat_special char /tmp/repo22-g3/mnt/char-large 2748 344865
|
||||
./stat_special block /tmp/repo22-g3/mnt/block-large 2748 344865
|
||||
./stat_special fifo /tmp/repo22-g3/mnt/fifo
|
||||
stat -f 'name=%N type=%HT size=%z blocks=%b gen=%v' \
|
||||
/tmp/repo22-g3/mnt/char-large \
|
||||
/tmp/repo22-g3/mnt/block-large \
|
||||
/tmp/repo22-g3/mnt/fifo
|
||||
|
||||
## Expected Results
|
||||
|
||||
All type/rdev probes pass; each special inode has size and st_blocks zero and
|
||||
a nonzero generation. Record both fixture hashes and clean each mount/md.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: access - Allowed Operations
|
||||
|
||||
**Test ID**: TC057-access-allowed
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a non-root credential receives read and execute access allowed by the
|
||||
recorded mode bits on the read-only mount.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run with the native nobody credential:
|
||||
|
||||
su -m nobody -c './g3_vfs_probe expect-success access-read /tmp/repo22-g3/mnt/testdir/file.txt'
|
||||
su -m nobody -c './g3_vfs_probe expect-success access-exec /tmp/repo22-g3/mnt/testdir'
|
||||
su -m nobody -c './g3_vfs_probe expect-success access-exec /tmp/repo22-g3/mnt/testdir/script.sh'
|
||||
su -m nobody -c './g3_vfs_probe expect-success open-read /tmp/repo22-g3/mnt/testdir/file.txt'
|
||||
|
||||
## Expected Results
|
||||
|
||||
All four direct checks report success with errno 0. Record the nobody uid,
|
||||
fixture modes, command output, and cleanup.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: access - Denied Operations
|
||||
|
||||
**Test ID**: TC058-access-denied
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify direct access checks distinguish permission denial from read-only
|
||||
modification denial for a non-root credential.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
su -m nobody -c './g3_vfs_probe expect-error access-read /tmp/repo22-g3/mnt/testdir/rootonly.txt 13'
|
||||
su -m nobody -c './g3_vfs_probe expect-error access-read /tmp/repo22-g3/mnt/testdir/writeonly.txt 13'
|
||||
su -m nobody -c './g3_vfs_probe expect-error access-exec /tmp/repo22-g3/mnt/testdir/noexec.txt 13'
|
||||
su -m nobody -c './g3_vfs_probe expect-error access-write /tmp/repo22-g3/mnt/testdir/file.txt 30'
|
||||
|
||||
## Expected Results
|
||||
|
||||
Mode-bit denials report EACCES (13); requested modification of the regular
|
||||
file reports EROFS (30). Record exact helper output and cleanup.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: readlink Exact Targets
|
||||
|
||||
**Test ID**: TC059-readlink
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify short, relative, broken, and long symlink targets are returned exactly,
|
||||
including the long inline target length and bytes.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./g3_vfs_probe readlink /tmp/repo22-g3/mnt/testdir/shortlink
|
||||
./g3_vfs_probe readlink /tmp/repo22-g3/mnt/testdir/relative-link
|
||||
./g3_vfs_probe readlink /tmp/repo22-g3/mnt/testdir/broken-link
|
||||
./g3_vfs_probe readlink /tmp/repo22-g3/mnt/testdir/long-link
|
||||
cmp fixtures/vfs/source/testdir/file.txt \
|
||||
/tmp/repo22-g3/mnt/testdir/shortlink
|
||||
./g3_vfs_probe expect-error stat \
|
||||
/tmp/repo22-g3/mnt/testdir/broken-link 2
|
||||
|
||||
## Expected Results
|
||||
|
||||
The helper reports exact targets and hashes: shortlink is file.txt, the
|
||||
relative link is subdir/child.txt, broken-link is missing-target, and long-link
|
||||
has the recorded 119-byte target. Following valid links matches source; the
|
||||
broken target returns errno 2. Record output and cleanup.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: pathconf Queries
|
||||
|
||||
**Test ID**: TC060-pathconf
|
||||
**Category**: VFS Integration
|
||||
**Priority**: High
|
||||
**Latest Result**: PASS on exact cdba7e54f KLD; see
|
||||
tests/results/manual/2026-08-09T1120Z-tc060-fix/manual-test-report.md and the
|
||||
resolved issues/TC060-pathconf-standard-values.md.
|
||||
|
||||
## Objective
|
||||
|
||||
Verify direct pathconf(2) results for EROFS limits and read-only conventions.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./g3_vfs_probe pathconf /tmp/repo22-g3/mnt/testdir
|
||||
|
||||
## Expected Results
|
||||
|
||||
The helper must exit zero and report name_max=255, a positive path_max,
|
||||
filesizebits=64, a positive link_max, no_trunc=1, and chown_restricted=1.
|
||||
EINVAL for either standard query is a kernel failure, not an environmental
|
||||
skip. Record every value/errno and cleanup.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: chmod Rejection
|
||||
|
||||
**Test ID**: TC061-setattr-chmod-reject
|
||||
**Category**: Read-Only Enforcement
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a direct chmod request returns EROFS and leaves metadata unchanged.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/file.txt > TC061-before.txt
|
||||
./g3_vfs_probe expect-error chmod \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt 30
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/file.txt > TC061-after.txt
|
||||
cmp TC061-before.txt TC061-after.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
chmod reports errno 30 and complete metadata remains unchanged. Record output,
|
||||
fixture hash, and cleanup.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: chown Rejection
|
||||
|
||||
**Test ID**: TC062-setattr-chown-reject
|
||||
**Category**: Read-Only Enforcement
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a privileged direct chown request returns EROFS and leaves ownership
|
||||
unchanged.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs as root and run:
|
||||
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/file.txt > TC062-before.txt
|
||||
./g3_vfs_probe expect-error chown \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt 30
|
||||
./g3_vfs_probe stat /tmp/repo22-g3/mnt/testdir/file.txt > TC062-after.txt
|
||||
cmp TC062-before.txt TC062-after.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
chown to uid/gid 65534 reports errno 30 and metadata remains unchanged. Record
|
||||
output and cleanup.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Write, Truncate, and Create Rejection
|
||||
|
||||
**Test ID**: TC063-setattr-write-reject
|
||||
**Category**: Read-Only Enforcement
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify direct open-for-write, truncate, and create requests return EROFS and
|
||||
leave the mounted tree unchanged.
|
||||
|
||||
## Procedure
|
||||
|
||||
Mount vfs/vfs-plain.erofs and run:
|
||||
|
||||
sha256 /tmp/repo22-g3/mnt/testdir/file.txt > TC063-before.txt
|
||||
./g3_vfs_probe expect-error open-rdwr \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt 30
|
||||
./g3_vfs_probe expect-error truncate \
|
||||
/tmp/repo22-g3/mnt/testdir/file.txt 30
|
||||
./g3_vfs_probe expect-error create \
|
||||
/tmp/repo22-g3/mnt/testdir/newfile.txt 30
|
||||
sha256 /tmp/repo22-g3/mnt/testdir/file.txt > TC063-after.txt
|
||||
cmp TC063-before.txt TC063-after.txt
|
||||
test ! -e /tmp/repo22-g3/mnt/testdir/newfile.txt
|
||||
|
||||
## Expected Results
|
||||
|
||||
All mutation syscalls report errno 30, the file hash is unchanged, and no new
|
||||
entry exists. Record output and cleanup.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: FreeBSD 15 Local Vnode Pager
|
||||
|
||||
**Test ID**: TC064-vop-getpages-normal
|
||||
**Category**: VM Integration
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the exact KLD resolves FreeBSD 15 local pager entry points and real
|
||||
plain/LZ4 vnode mappings fault data through the pager.
|
||||
|
||||
## Procedure
|
||||
|
||||
Record unresolved KLD symbols with nm -u. On separate fresh mounts of
|
||||
vfs/vfs-plain.erofs and vfs/vfs-lz4.erofs, run:
|
||||
|
||||
./mmap_fault /tmp/repo22-g3/mnt/pager.bin
|
||||
|
||||
## Expected Results
|
||||
|
||||
The KLD loads with vnode_pager_local_getpages and
|
||||
vnode_pager_local_getpages_async resolved. Both helpers report identical
|
||||
21211-byte FNV hashes, six random faults, partial-EOF zeroing, expected child
|
||||
SIGBUS, denied writable shared mapping, private COW, and O_RDWR EROFS. Record
|
||||
both image hashes, dmesg, and per-mount cleanup.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: mmap Through VOP_GETPAGES
|
||||
|
||||
**Test ID**: TC065-vop-getpages-mmap
|
||||
**Category**: VM Integration
|
||||
**Priority**: Critical
|
||||
|
||||
## Objective
|
||||
|
||||
Verify page-fault-driven reads, EOF semantics, and private/shared mapping
|
||||
behavior for plain and compressed EROFS files.
|
||||
|
||||
## Procedure
|
||||
|
||||
On separate fresh mounts of vfs/vfs-plain.erofs and vfs/vfs-lz4.erofs:
|
||||
|
||||
./mmap_fault /tmp/repo22-g3/mnt/pager.bin
|
||||
|
||||
## Expected Results
|
||||
|
||||
Random and sequential mapped bytes match pread exactly; the partial EOF page
|
||||
is zero, the next full page produces the helper's expected child SIGBUS,
|
||||
writable MAP_SHARED is EACCES, MAP_PRIVATE COW succeeds, and O_RDWR is EROFS.
|
||||
The plain and LZ4 logical FNV hashes are identical. Direct read utilities are
|
||||
not acceptance evidence. Record dmesg and cleanup.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: Unsupported BMAP with Pager Fallback
|
||||
|
||||
**Test ID**: TC066-vop-bmap-unsupported
|
||||
**Category**: VM Integration
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the exact source KLD keeps erofs_bmap as EOPNOTSUPP while FreeBSD's
|
||||
local vnode pager successfully faults plain and compressed files through
|
||||
VOP_READ.
|
||||
|
||||
## Procedure
|
||||
|
||||
Audit the exact archived source registration and record KLD symbols. Then, on
|
||||
fresh mounts of vfs/vfs-plain.erofs and vfs/vfs-lz4.erofs, run:
|
||||
|
||||
./mmap_fault /tmp/repo22-g3/mnt/pager.bin
|
||||
|
||||
## Expected Results
|
||||
|
||||
The source returns EOPNOTSUPP from erofs_bmap and registers both local pager
|
||||
entry points. Both real mmap tests pass; dmesg has no "No strategy for
|
||||
buffer", assertion, trap, or panic. Record source/KLD/image hashes and cleanup.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Test Case: Shared xattr scan found
|
||||
|
||||
**Test ID**: TC067-shared-xattr-scan-found
|
||||
**Fixture**: `basic.erofs`, `/shared-a`, `/shared-b`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify that shared IDs are scanned after inline entries and return exact data.
|
||||
The generator manifest must show `shared_key` in the shared table and `local`
|
||||
inline on `/shared-a`.
|
||||
|
||||
## Manual steps
|
||||
|
||||
Mount `basic.erofs` using `G4-MANUAL-SETUP.md`, then run:
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/shared-a
|
||||
getextattr -qq -x user shared_key /mnt/repo22-g4/shared-a
|
||||
getextattr -qq -x user shared_key /mnt/repo22-g4/shared-b
|
||||
getextattr -qq -x user local /mnt/repo22-g4/shared-a
|
||||
stat -f 'size=%z inode=%i' /mnt/repo22-g4/shared-a
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Both shared reads equal `shared-value\0exact` byte-for-byte, the inline read is
|
||||
`in-bounds-local`, and list output contains all four expected user names.
|
||||
Unmount and detach before the next TC.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Test Case: Shared xattr scan not found
|
||||
|
||||
**Test ID**: TC068-shared-xattr-scan-notfound
|
||||
**Fixture**: `basic.erofs`, `/shared-a`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify clean exhaustion of inline and shared scans and namespace isolation.
|
||||
|
||||
## Manual steps
|
||||
|
||||
Mount `basic.erofs`, list the user namespace, then capture both misses:
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/shared-a
|
||||
truss -o /tmp/tc068-name.truss \
|
||||
getextattr -qq user nonexistent /mnt/repo22-g4/shared-a
|
||||
truss -o /tmp/tc068-ns.truss \
|
||||
getextattr -qq system shared_key /mnt/repo22-g4/shared-a
|
||||
grep extattr_get_file /tmp/tc068-*.truss
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Both kernel calls return `ENOATTR` (87), with no `EINTEGRITY`, delay, or name
|
||||
leak into the FreeBSD `system` namespace. Unmount and detach the image.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Test Case: List multiple shared xattrs
|
||||
|
||||
**Test ID**: TC069-shared-xattr-list-multiple
|
||||
**Fixture**: `basic.erofs`, `/shared-multi`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify FreeBSD's length-prefixed extattr list for several shared user entries.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/shared-multi
|
||||
getextattr -qq -x user shared_key /mnt/repo22-g4/shared-multi
|
||||
getextattr -qq -x user shared_comment /mnt/repo22-g4/shared-multi
|
||||
getextattr -qq -x user shared_binary /mnt/repo22-g4/shared-multi
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The list contains exactly `shared_key`, `shared_comment`, and `shared_binary`,
|
||||
without duplicates. Values are `shared-value\0exact`, `shared-comment`, and
|
||||
bytes `00` through `0f`. Perform the standard unmount/md cleanup.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: Shared trusted xattr
|
||||
|
||||
**Test ID**: TC070-shared-trusted-xattr
|
||||
**Fixture**: `basic.erofs`, `/trusted-shared-a`, `/trusted-shared-b`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a shared Linux `trusted.*` entry through FreeBSD extattr semantics.
|
||||
The transformer must record `e_name_index: 1 -> 4` for the shared record.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/trusted-shared-a
|
||||
getextattr -qq -x system trusted.config /mnt/repo22-g4/trusted-shared-a
|
||||
getextattr -qq -x system trusted.config /mnt/repo22-g4/trusted-shared-b
|
||||
su -m nobody -c 'getextattr system trusted.config /mnt/repo22-g4/trusted-shared-a'
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Root receives `trusted-shared-value` from both files. FreeBSD exposes the full
|
||||
`trusted.config` name in namespace `system`, not a namespace named `trusted`.
|
||||
The unprivileged system-namespace request is denied. Clean up the mount/md.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: Shared security xattr
|
||||
|
||||
**Test ID**: TC071-shared-security-xattr
|
||||
**Fixture**: `basic.erofs`, `/security-shared-a`, `/security-shared-b`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a shared Linux `security.*` entry mapped to FreeBSD namespace `system`.
|
||||
The transformer must record `e_name_index: 1 -> 6`.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/security-shared-a
|
||||
getextattr -qq -x system security.selinux /mnt/repo22-g4/security-shared-a
|
||||
getextattr -qq -x system security.selinux /mnt/repo22-g4/security-shared-b
|
||||
truss -o /tmp/tc071.truss getextattr -qq system security.missing \
|
||||
/mnt/repo22-g4/security-shared-a
|
||||
grep extattr_get_file /tmp/tc071.truss
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Both values are exactly `system_u:object_r:shared_repo22_t:s0\0`; the missing
|
||||
name returns `ENOATTR` (87). Unmount and detach.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Test Case: List the FreeBSD system namespace
|
||||
|
||||
**Test ID**: TC072-shared-system-xattr-list
|
||||
**Fixture**: `basic.erofs`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify that trusted, security, and POSIX ACL indexes are listed only through
|
||||
FreeBSD namespace `system` with their ABI names.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/trusted-shared-a
|
||||
lsextattr system /mnt/repo22-g4/security-shared-a
|
||||
lsextattr system /mnt/repo22-g4/acl-unordered
|
||||
lsextattr user /mnt/repo22-g4/trusted-shared-a
|
||||
stat -f '%HT %Sp' /mnt/repo22-g4/trusted-shared-a \
|
||||
/mnt/repo22-g4/security-shared-a /mnt/repo22-g4/acl-unordered
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The three system lists contain `trusted.config`, `security.selinux`, and
|
||||
`posix_acl_access`, respectively. The trusted file's user list is empty.
|
||||
Unmount and detach.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Test Case: Plain metabox container
|
||||
|
||||
**Test ID**: TC073-metabox-container
|
||||
**Fixture**: `metabox-plain.erofs`, `/metabox-a`, `/metabox-b`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify metadata and xattrs read from a plain regular metabox carrier. Before
|
||||
guest use, require manifest fields `METABOX`, `sb_extslots=1`, relocated
|
||||
`meta_blkaddr`, `metabox_nid`, bit-63 dirent NIDs, and image/source hashes.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
unit=$(mdconfig -a -t vnode -f /tmp/repo22-g4/images/metabox-plain.erofs)
|
||||
mount -t erofs -o ro /dev/${unit} /mnt/repo22-g4
|
||||
stat -f 'mode=%Sp size=%z inode=%i' /mnt/repo22-g4/metabox-a \
|
||||
/mnt/repo22-g4/metabox-b
|
||||
sha256 -q /mnt/repo22-g4/metabox-a /mnt/repo22-g4/metabox-b
|
||||
lsextattr user /mnt/repo22-g4/metabox-a
|
||||
getextattr -qq -x user metaboxshared /mnt/repo22-g4/metabox-a
|
||||
getextattr -qq -x user metaboxshared /mnt/repo22-g4/metabox-b
|
||||
umount /mnt/repo22-g4
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The inode numbers retain bit 63; file hashes match the generated source;
|
||||
`metaboxshared` is `nonzero-base` for both files. No mount/md remains.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: Multiple inline user xattrs
|
||||
|
||||
**Test ID**: TC074-inline-user-xattr-multiple
|
||||
**Fixture**: `basic.erofs`, `/inline-multi`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify list/get across several inline user entries, including embedded NUL and
|
||||
binary values. Qualify their inline offsets in `fixture-manifest.json` first.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/inline-multi
|
||||
getextattr -qq -x user attr1 /mnt/repo22-g4/inline-multi
|
||||
getextattr -qq -x user attr2 /mnt/repo22-g4/inline-multi
|
||||
getextattr -qq -x user attr3 /mnt/repo22-g4/inline-multi
|
||||
stat -f 'mode=%Sp size=%z' /mnt/repo22-g4/inline-multi
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Names are `attr1`, `attr2`, `attr3`; values are `one`, `two\0binary`, and
|
||||
bytes `00` through `1f`. Unmount and detach.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: Inline trusted xattr
|
||||
|
||||
**Test ID**: TC075-inline-trusted-xattr
|
||||
**Fixture**: `basic.erofs`, `/inline-trusted`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify an inline entry transformed to Linux index 4 and exposed through the
|
||||
FreeBSD system namespace.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/inline-trusted
|
||||
getextattr -qq -x system trusted.admin /mnt/repo22-g4/inline-trusted
|
||||
truss -o /tmp/tc075.truss getextattr -qq user admin \
|
||||
/mnt/repo22-g4/inline-trusted
|
||||
grep extattr_get_file /tmp/tc075.truss
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
`trusted.admin` equals `trusted-inline-value`; the user-namespace lookup
|
||||
returns `ENOATTR` (87). Perform standard cleanup.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Test Case: Inline security xattrs
|
||||
|
||||
**Test ID**: TC076-inline-security-xattr
|
||||
**Fixture**: `basic.erofs`, `/inline-security`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify inline Linux index 6 entries and binary-value preservation through
|
||||
FreeBSD namespace `system`.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/inline-security
|
||||
getextattr -qq -x system security.capability /mnt/repo22-g4/inline-security
|
||||
getextattr -qq -x system security.selinux /mnt/repo22-g4/inline-security
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Capability bytes are `0100000200000000aabbccdd`; SELinux bytes are
|
||||
`system_u:object_r:repo22_t:s0\0`. Unmount and detach.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: Long-prefix user xattr
|
||||
|
||||
**Test ID**: TC077-long-prefix-user-xattr
|
||||
**Fixture**: `basic.erofs`, `/prefix-user-0`, `/prefix-user-1`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify reconstruction of a long user name from packed prefix ID 0. The helper
|
||||
must self-check prefix record base index 1 and infix
|
||||
`repo22.application.component.`.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/prefix-user-0
|
||||
getextattr -qq -x user repo22.application.component.setting \
|
||||
/mnt/repo22-g4/prefix-user-0
|
||||
getextattr -qq -x user repo22.application.component.setting \
|
||||
/mnt/repo22-g4/prefix-user-1
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The full name is listed once and the values are `prefix-value-0` and
|
||||
`prefix-value-1`. Unmount and detach.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Test Case: Long-prefix trusted xattr
|
||||
|
||||
**Test ID**: TC078-long-prefix-trusted-xattr
|
||||
**Fixture**: `basic.erofs`, `/prefix-trusted-0`, `/prefix-trusted-1`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify packed long-prefix reconstruction after the transformer changes prefix
|
||||
record 1 from user base index 1 to trusted base index 4.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/prefix-trusted-0
|
||||
getextattr -qq -x system trusted.repo22.trusted.deep.setting \
|
||||
/mnt/repo22-g4/prefix-trusted-0
|
||||
getextattr -qq -x system trusted.repo22.trusted.deep.setting \
|
||||
/mnt/repo22-g4/prefix-trusted-1
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The full trusted name appears in FreeBSD namespace `system`; values are
|
||||
`trusted-prefix-value-0` and `trusted-prefix-value-1`. Clean up.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Test Case: Packed prefix table
|
||||
|
||||
**Test ID**: TC079-packed-prefix-table
|
||||
**Fixture**: `basic.erofs`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify a non-plain prefix table carried by the packed inode generated by
|
||||
erofs-utils 1.8.6.
|
||||
|
||||
## Layout qualification
|
||||
|
||||
```sh
|
||||
dump.erofs -s "$run/images/basic.erofs"
|
||||
python3 tests/g4_fixtures.py verify --output "$run"
|
||||
```
|
||||
|
||||
Require `xattr_prefix_count=2`, nonzero `packed_nid`, prefix start 0, user
|
||||
record `(base=1, infix=repo22.application.component.)`, trusted record
|
||||
`(base=4, infix=repo22.trusted.deep.)`, and matching image hash.
|
||||
|
||||
## Guest observations
|
||||
|
||||
```sh
|
||||
getextattr -qq -x user repo22.application.component.setting \
|
||||
/mnt/repo22-g4/prefix-user-2
|
||||
getextattr -qq -x system trusted.repo22.trusted.deep.setting \
|
||||
/mnt/repo22-g4/prefix-trusted-2
|
||||
stat -f 'mode=%Sp inode=%i' /mnt/repo22-g4/prefix-user-2 \
|
||||
/mnt/repo22-g4/prefix-trusted-2
|
||||
```
|
||||
|
||||
Both values must end in `-2`; cleanup must be empty.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: Prefix table lookup
|
||||
|
||||
**Test ID**: TC080-prefix-table-lookup
|
||||
**Fixture**: `basic.erofs`, `/prefix-user-0` through `/prefix-user-3`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify repeated prefix-ID lookup and a clean missing-suffix result.
|
||||
|
||||
## Manual steps
|
||||
|
||||
Run the following lookup separately for suffix files 0, 1, 2, and 3:
|
||||
|
||||
```sh
|
||||
getextattr -qq -x user repo22.application.component.setting \
|
||||
/mnt/repo22-g4/prefix-user-N
|
||||
truss -o /tmp/tc080.truss getextattr -qq user \
|
||||
repo22.application.component.missing /mnt/repo22-g4/prefix-user-0
|
||||
grep extattr_get_file /tmp/tc080.truss
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Values are `prefix-value-N` for each file; the missing suffix is `ENOATTR`
|
||||
(87), not an integrity failure. Unmount and detach.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Test Case: Metabox-backed shared xattrs
|
||||
|
||||
**Test ID**: TC081-metabox-backed-xattr
|
||||
**Fixture**: `metabox-plain.erofs`, `/metabox-a`, `/metabox-b`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify shared entries, inline entries, and long-prefix shared entries from a
|
||||
metabox logical stream. Require `SHARED_EA_IN_METABOX`, `xattr_blkaddr=1`,
|
||||
carrier size/bounds, shared IDs, and prefix fields in the generator manifest.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/metabox-a
|
||||
getextattr -qq -x user metaboxshared /mnt/repo22-g4/metabox-a
|
||||
getextattr -qq -x user metaboxshared /mnt/repo22-g4/metabox-b
|
||||
getextattr -qq -x user shared-prefix-key /mnt/repo22-g4/metabox-a
|
||||
getextattr -qq -x user repo22.application.component.setting \
|
||||
/mnt/repo22-g4/metabox-a
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Values are `nonzero-base`, `nonzero-base`, `shared-value`, and
|
||||
`long-prefix-value`; all names list once. Clean up.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: FreeBSD system namespace subset
|
||||
|
||||
**Test ID**: TC082-system-namespace-subset
|
||||
**Fixture**: `basic.erofs`, `/acl-unordered`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify POSIX ACL exposure in FreeBSD namespace `system` and isolation from
|
||||
namespace `user`.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr system /mnt/repo22-g4/acl-unordered
|
||||
getextattr -qq -x system posix_acl_access /mnt/repo22-g4/acl-unordered
|
||||
getfacl -n /mnt/repo22-g4/acl-unordered
|
||||
truss -o /tmp/tc082.truss getextattr -qq user posix_acl_access \
|
||||
/mnt/repo22-g4/acl-unordered
|
||||
grep extattr_get_file /tmp/tc082.truss
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
Raw ACL starts with little-endian version 2; `getfacl` shows named users 3002
|
||||
then 2002. The user-namespace request returns `ENOATTR` (87). Clean up.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Test Case: User namespace subset
|
||||
|
||||
**Test ID**: TC083-user-namespace-subset
|
||||
**Fixture**: `basic.erofs`, `/user-subset`
|
||||
|
||||
## Objective
|
||||
|
||||
Verify several application user xattrs without exposing them through FreeBSD
|
||||
namespace `system`.
|
||||
|
||||
## Manual steps
|
||||
|
||||
```sh
|
||||
lsextattr user /mnt/repo22-g4/user-subset
|
||||
getextattr -qq -x user comment /mnt/repo22-g4/user-subset
|
||||
getextattr -qq -x user author /mnt/repo22-g4/user-subset
|
||||
getextattr -qq -x user checksum /mnt/repo22-g4/user-subset
|
||||
getextattr -qq -x user com.repo22.app.setting /mnt/repo22-g4/user-subset
|
||||
lsextattr system /mnt/repo22-g4/user-subset
|
||||
```
|
||||
|
||||
## Expected results
|
||||
|
||||
The user values are `subset-comment`, `repo22`,
|
||||
`sha256:0123456789abcdef`, and `enabled`. The system list is empty. Clean up.
|
||||
@@ -0,0 +1,71 @@
|
||||
# Test Case: LZ4 Compression Basic Support
|
||||
|
||||
**Test ID**: TC084-lz4-basic
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: Critical
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify basic LZ4 compression support for reading compressed files.
|
||||
|
||||
## Preconditions
|
||||
- EROFS image with LZ4 compression: `test-lz4-basic.erofs`
|
||||
- Test file: `/files/test-lz4.txt` (1MB, highly compressible)
|
||||
- Mount point: `/mnt/test`
|
||||
|
||||
## Test Steps
|
||||
1. Mount the LZ4-compressed image:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test
|
||||
```
|
||||
|
||||
2. Read entire compressed file:
|
||||
```
|
||||
cat /mnt/test/files/test-lz4.txt > /tmp/output.txt
|
||||
```
|
||||
|
||||
3. Verify file size:
|
||||
```
|
||||
stat -f %z /mnt/test/files/test-lz4.txt
|
||||
```
|
||||
|
||||
4. Compare with reference (uncompressed):
|
||||
```
|
||||
cmp /tmp/output.txt /tmp/reference.txt
|
||||
```
|
||||
|
||||
5. Test multiple LZ4-compressed files:
|
||||
```
|
||||
for f in /mnt/test/files/lz4-*.txt; do
|
||||
cat "$f" > /dev/null
|
||||
done
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 1: Mount succeeds
|
||||
- Step 2: File read successfully, decompressed transparently
|
||||
- Step 3: Size matches original uncompressed size (1048576 bytes)
|
||||
- Step 4: Files identical (cmp returns 0)
|
||||
- Step 5: All LZ4 files read without errors
|
||||
|
||||
## Verification Method
|
||||
- Verify decompression transparent to application
|
||||
- Confirm data integrity after decompression
|
||||
- Test LZ4 decompression performance acceptable
|
||||
- Verify compressed file sizes smaller than uncompressed
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u md0
|
||||
rm /tmp/output.txt
|
||||
```
|
||||
|
||||
## Notes
|
||||
- LZ4 provides fast decompression with moderate compression ratio
|
||||
- EROFS uses LZ4 for general-purpose compression
|
||||
- Related tests: TC003 (LZ4 compressed read), TC085 (large files)
|
||||
@@ -0,0 +1,78 @@
|
||||
# Test Case: LZ4 Compression Large File Handling
|
||||
|
||||
**Test ID**: TC085-lz4-large-file
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify LZ4 decompression correctness for large files (>100MB).
|
||||
|
||||
## Preconditions
|
||||
- Generated image: `images/lz4-large.erofs`
|
||||
- Test file: `/large.bin`, exactly 268435456 bytes
|
||||
- Reference: `sources/large/large.bin` and its generated SHA256
|
||||
- Mount point: `/mnt/test`
|
||||
|
||||
## Test Steps
|
||||
1. Mount the image:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test
|
||||
```
|
||||
|
||||
2. Verify file size reported correctly:
|
||||
```
|
||||
stat -f %z /mnt/test/files/large-lz4.bin
|
||||
```
|
||||
|
||||
3. Read entire file and compute checksum:
|
||||
```
|
||||
sha256 -q /mnt/test/large.bin
|
||||
sha256 -q sources/large/large.bin
|
||||
cmp sources/large/large.bin /mnt/test/large.bin
|
||||
```
|
||||
|
||||
4. Test partial reads at various offsets:
|
||||
```
|
||||
read_probe pread /mnt/test/large.bin 52428800 10485760 guest.bin
|
||||
read_probe pread sources/large/large.bin 52428800 10485760 source.bin
|
||||
cmp source.bin guest.bin
|
||||
read_probe pread /mnt/test/large.bin 209715200 10485760 guest.bin
|
||||
read_probe pread sources/large/large.bin 209715200 10485760 source.bin
|
||||
cmp source.bin guest.bin
|
||||
```
|
||||
|
||||
5. Test random access reads:
|
||||
```
|
||||
# Compare both guest ranges with the same source offsets.
|
||||
read_probe pread /mnt/test/large.bin 4096000 4096 chunk1
|
||||
read_probe pread /mnt/test/large.bin 204800000 4096 chunk2
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 2: Size is 268435456 bytes (256MB)
|
||||
- Step 3: Checksum matches reference value
|
||||
- Step 4: Partial reads succeed, no errors
|
||||
- Step 5: Random access works correctly
|
||||
|
||||
## Verification Method
|
||||
- Verify data integrity via checksum
|
||||
- Confirm partial/random reads decompress correctly
|
||||
- Test memory usage during decompression reasonable
|
||||
- Verify no memory leaks or buffer overflows
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u "${unit#md}"
|
||||
rm /tmp/chunk1 /tmp/chunk2
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Large file decompression tests pcluster handling
|
||||
- LZ4 decompression should be streaming (low memory)
|
||||
- Related tests: TC089 (pcluster mapping)
|
||||
@@ -0,0 +1,57 @@
|
||||
# Test Case: LZ4 Sequential Read Correctness
|
||||
|
||||
**Test ID**: TC086-lz4-sequential-read
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify complete sequential reads of an LZ4-compressed file with two request
|
||||
sizes against the original source bytes. Record timings only; repo22 exposes no
|
||||
filesystem-specific DTrace provider and this test has no fixed throughput
|
||||
threshold.
|
||||
|
||||
## Fixture
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc086.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
dump.erofs -s "$work/fixtures/valid-lz4.erofs"
|
||||
dump.erofs --path=/compressed.bin -e "$work/fixtures/valid-lz4.erofs"
|
||||
```
|
||||
|
||||
The dump must identify `/compressed.bin` as compressed LZ4 data with real
|
||||
physical extents.
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
```sh
|
||||
mkdir "$work/mnt"
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/valid-lz4.erofs")
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt"
|
||||
|
||||
expected=$(sha256 -q "$work/fixtures/source/compressed.bin")
|
||||
actual=$(sha256 -q "$work/mnt/compressed.bin")
|
||||
test "$actual" = "$expected"
|
||||
|
||||
/usr/bin/time -p dd if="$work/mnt/compressed.bin" \
|
||||
of="$work/read-4k.bin" bs=4096 2>"$work/time-4k.txt"
|
||||
cmp "$work/fixtures/source/compressed.bin" "$work/read-4k.bin"
|
||||
/usr/bin/time -p dd if="$work/mnt/compressed.bin" \
|
||||
of="$work/read-1m.bin" bs=1048576 2>"$work/time-1m.txt"
|
||||
cmp "$work/fixtures/source/compressed.bin" "$work/read-1m.bin"
|
||||
cat "$work/time-4k.txt" "$work/time-1m.txt"
|
||||
|
||||
umount "$work/mnt"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
Both complete outputs compare byte-for-byte with the source and both hashes
|
||||
match. Timing values are recorded with guest CPU, VM, and storage context; one
|
||||
buffer size is not required to outperform the other.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Test Case: LZ4 Deterministic Random-Offset Reads
|
||||
|
||||
**Test ID**: TC087-lz4-random-read
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
|
||||
## Objective
|
||||
|
||||
Verify non-sequential reads from deterministic offsets in an LZ4-compressed
|
||||
file and compare every returned byte with the source. `$RANDOM` and timing-only
|
||||
checks are not evidence of data correctness.
|
||||
|
||||
## Fixture and Helper
|
||||
|
||||
```sh
|
||||
work=$(mktemp -d /tmp/repo22-tc087.XXXXXX)
|
||||
tests/prepare_error_fixtures.sh "$work/fixtures"
|
||||
cc -O2 -Wall -Wextra -std=c17 tests/read_probe.c -o "$work/read_probe"
|
||||
dump.erofs --path=/compressed.bin -e "$work/fixtures/valid-lz4.erofs"
|
||||
```
|
||||
|
||||
## FreeBSD Procedure
|
||||
|
||||
```sh
|
||||
mkdir "$work/mnt"
|
||||
unit=$(mdconfig -a -t vnode -f "$work/fixtures/valid-lz4.erofs")
|
||||
mount -t erofs -o ro "/dev/$unit" "$work/mnt"
|
||||
size=$(stat -f %z "$work/fixtures/source/compressed.bin")
|
||||
test "$size" -gt 1052672
|
||||
|
||||
index=0
|
||||
for offset in 0 4096 65536 1048576 $((size - 4096)); do
|
||||
"$work/read_probe" pread "$work/mnt/compressed.bin" \
|
||||
"$offset" 4096 "$work/guest-$index.bin"
|
||||
"$work/read_probe" pread "$work/fixtures/source/compressed.bin" \
|
||||
"$offset" 4096 "$work/source-$index.bin"
|
||||
cmp "$work/source-$index.bin" "$work/guest-$index.bin"
|
||||
index=$((index + 1))
|
||||
done
|
||||
|
||||
umount "$work/mnt"
|
||||
mdconfig -d -u "${unit#md}"
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
All five fixed reads, including the final 4 KiB of the file, return exactly
|
||||
4096 bytes and compare equal to their corresponding source ranges. No
|
||||
performance ordering is asserted.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Test Case: LZ4 Compression Configuration Handling
|
||||
|
||||
**Test ID**: TC088-lz4-config-handling
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: Medium
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify correct handling of different LZ4 compression configurations.
|
||||
|
||||
## Preconditions
|
||||
- Multiple EROFS images with different LZ4 configs:
|
||||
- `lz4-pcluster-4k.erofs` (4KB pcluster)
|
||||
- `lz4-pcluster-64k.erofs` (64KB pcluster)
|
||||
- `lz4-pcluster-256k.erofs` (256KB pcluster)
|
||||
- Test file in each: `/files/test.dat` (identical content)
|
||||
- Mount points: `/mnt/test1`, `/mnt/test2`, `/mnt/test3`
|
||||
- Generate the images explicitly with `mkfs.erofs 1.8.6`:
|
||||
```
|
||||
mkfs.erofs -zlz4 -C4096 lz4-pcluster-4k.erofs source
|
||||
mkfs.erofs -zlz4 -C65536 lz4-pcluster-64k.erofs source
|
||||
mkfs.erofs -zlz4 -C262144 lz4-pcluster-256k.erofs source
|
||||
```
|
||||
- Confirm the requested feature/configuration with `dump.erofs -s` before
|
||||
treating an image as a valid fixture.
|
||||
|
||||
## Test Steps
|
||||
1. Mount all three images:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test1
|
||||
mount -t erofs /dev/md1 /mnt/test2
|
||||
mount -t erofs /dev/md2 /mnt/test3
|
||||
```
|
||||
|
||||
2. Read from each and verify identical output:
|
||||
```
|
||||
sha256 /mnt/test1/files/test.dat
|
||||
sha256 /mnt/test2/files/test.dat
|
||||
sha256 /mnt/test3/files/test.dat
|
||||
```
|
||||
|
||||
3. Record image sizes without assuming a monotonic compression ratio:
|
||||
```
|
||||
stat -f %z /root/lz4-pcluster-4k.erofs
|
||||
stat -f %z /root/lz4-pcluster-64k.erofs
|
||||
stat -f %z /root/lz4-pcluster-256k.erofs
|
||||
```
|
||||
|
||||
4. Verify the same offset read with each pcluster size. Timing is diagnostic
|
||||
only and is not a functional pass criterion:
|
||||
```
|
||||
time dd if=/mnt/test1/files/test.dat of=/dev/null bs=4K skip=100 count=10
|
||||
time dd if=/mnt/test2/files/test.dat of=/dev/null bs=4K skip=100 count=10
|
||||
time dd if=/mnt/test3/files/test.dat of=/dev/null bs=4K skip=100 count=10
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 1: All mounts succeed
|
||||
- Step 2: All three checksums identical (data integrity)
|
||||
- Step 3: Image sizes are recorded for the exact corpus and mkfs version
|
||||
- Step 4: All reads succeed and return identical data at the tested offset
|
||||
|
||||
## Verification Method
|
||||
- Verify all pcluster configurations work correctly
|
||||
- Record pcluster size effects without assuming they are monotonic for every
|
||||
corpus or under a QEMU TCG guest
|
||||
- Test driver handles different configs transparently
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test1 /mnt/test2 /mnt/test3
|
||||
mdconfig -d -u "${unit1#md}"
|
||||
mdconfig -d -u "${unit2#md}"
|
||||
mdconfig -d -u "${unit3#md}"
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Pcluster size is compression unit (physical cluster)
|
||||
- Larger pcluster -> better compression, worse random access
|
||||
- Typical sizes: 4KB, 16KB, 64KB, 256KB
|
||||
- Related tests: TC089 (pcluster mapping)
|
||||
@@ -0,0 +1,69 @@
|
||||
# Test Case: LZ4 Compressed Physical Cluster Mapping (4KB)
|
||||
|
||||
**Test ID**: TC089-lz4-pcluster-4k
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify correct physical cluster (pcluster) mapping for LZ4 compression with 4KB pcluster size.
|
||||
|
||||
## Preconditions
|
||||
- EROFS image with LZ4, 4KB pcluster: `test-lz4-pcluster-4k.erofs`
|
||||
- Test file: `/files/test-4k.dat` (aligned to 4KB boundaries)
|
||||
- Mount point: `/mnt/test`
|
||||
|
||||
## Test Steps
|
||||
1. Mount the image:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test
|
||||
```
|
||||
|
||||
2. Read aligned to pcluster boundary (offset 0):
|
||||
```
|
||||
dd if=/mnt/test/files/test-4k.dat of=/tmp/out1 bs=4K count=1 skip=0
|
||||
```
|
||||
|
||||
3. Read aligned to pcluster boundary (offset 4K):
|
||||
```
|
||||
dd if=/mnt/test/files/test-4k.dat of=/tmp/out2 bs=4K count=1 skip=1
|
||||
```
|
||||
|
||||
4. Read unaligned (crosses pcluster boundary):
|
||||
```
|
||||
dd if=/mnt/test/files/test-4k.dat of=/tmp/out3 bs=2K count=2 skip=1
|
||||
```
|
||||
|
||||
5. Read spanning multiple pclusters:
|
||||
```
|
||||
dd if=/mnt/test/files/test-4k.dat of=/tmp/out4 bs=16K count=1
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 2: Single pcluster decompressed, correct data
|
||||
- Step 3: Adjacent pcluster decompressed, correct data
|
||||
- Step 4: Two pclusters decompressed for unaligned read
|
||||
- Step 5: Four pclusters decompressed (16K / 4K = 4)
|
||||
|
||||
## Verification Method
|
||||
- Verify pcluster boundaries handled correctly
|
||||
- Confirm unaligned reads work (may decompress extra pclusters)
|
||||
- Test each pcluster independently decompressible
|
||||
- Verify correct data returned for all read patterns
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u md0
|
||||
rm /tmp/out1 /tmp/out2 /tmp/out3 /tmp/out4
|
||||
```
|
||||
|
||||
## Notes
|
||||
- 4KB pcluster provides good random access performance
|
||||
- Each 4KB logical region compressed independently
|
||||
- Small pcluster = less compression, better random access
|
||||
- Related tests: TC090 (64KB pcluster)
|
||||
@@ -0,0 +1,72 @@
|
||||
# Test Case: LZ4 Compressed Physical Cluster Mapping (64KB)
|
||||
|
||||
**Test ID**: TC090-lz4-pcluster-64k
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify correct physical cluster mapping for LZ4 compression with 64KB pcluster size.
|
||||
|
||||
## Preconditions
|
||||
- EROFS image with LZ4, 64KB pcluster: `test-lz4-pcluster-64k.erofs`
|
||||
- Test file: `/files/test-64k.dat` (1MB, highly compressible)
|
||||
- Mount point: `/mnt/test`
|
||||
- Generate with `mkfs.erofs -zlz4 -C65536 test-lz4-pcluster-64k.erofs source`
|
||||
and confirm `compr_cfgs big_pcluster` with `dump.erofs -s`.
|
||||
|
||||
## Test Steps
|
||||
1. Mount the image:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test
|
||||
```
|
||||
|
||||
2. Read first pcluster (64KB):
|
||||
```
|
||||
dd if=/mnt/test/files/test-64k.dat of=/tmp/out1 bs=64K count=1
|
||||
```
|
||||
|
||||
3. Read small portion requiring full pcluster decompression:
|
||||
```
|
||||
dd if=/mnt/test/files/test-64k.dat of=/tmp/out2 bs=4K count=1 skip=1
|
||||
```
|
||||
|
||||
4. Read crossing pcluster boundary:
|
||||
```
|
||||
dd if=/mnt/test/files/test-64k.dat of=/tmp/cross bs=1 skip=65504 count=64
|
||||
dd if=/root/reference/test-64k.dat of=/tmp/cross.expected bs=1 skip=65504 count=64
|
||||
cmp /tmp/cross /tmp/cross.expected
|
||||
```
|
||||
|
||||
5. Record the physical extent layout:
|
||||
```
|
||||
dump.erofs --path=/files/test-64k.dat -e test-lz4-pcluster-64k.erofs
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 2: Full 64KB pcluster decompressed correctly
|
||||
- Step 3: Reading 4KB requires decompressing entire 64KB pcluster
|
||||
- Step 4: Boundary crossing handled correctly
|
||||
- Step 5: The fixture contains a real compressed big-pcluster extent
|
||||
|
||||
## Verification Method
|
||||
- Verify large pcluster decompression works
|
||||
- Confirm small reads still trigger full pcluster decompression
|
||||
- Test memory usage reasonable for 64KB decompression
|
||||
- Do not require a better compression ratio than 4KB for every corpus
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u md0
|
||||
rm /tmp/out* /tmp/cross /tmp/cross.expected
|
||||
```
|
||||
|
||||
## Notes
|
||||
- 64KB pcluster provides better compression at cost of random access
|
||||
- Common pcluster size for read-heavy workloads
|
||||
- Related tests: TC089 (4KB pcluster), TC088 (config handling)
|
||||
@@ -0,0 +1,76 @@
|
||||
# Test Case: LZ4 ztailpacking Data Path
|
||||
|
||||
**Test ID**: TC091-ztailpacking-basic
|
||||
|
||||
**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
|
||||
Its generated paths, source comparisons, structured corruption offsets, and
|
||||
cleanup rules supersede placeholder examples in this file.
|
||||
**Category**: Compression
|
||||
**Priority**: High
|
||||
**Regression**: None
|
||||
|
||||
## Objective
|
||||
Verify correct operation of ztailpacking (compressed tail packing) for LZ4-compressed files.
|
||||
|
||||
## Preconditions
|
||||
- EROFS image with ztailpacking enabled: `test-ztailpacking.erofs`
|
||||
- Test file: `/inline.dat` (64KB deterministic compressible data)
|
||||
- Mount point: `/mnt/test`
|
||||
- Generate with:
|
||||
```
|
||||
mkfs.erofs -zlz4 -C4096 -Eztailpacking test-ztailpacking.erofs source
|
||||
```
|
||||
- Before mounting, require `dump.erofs -s` to report `ztailpacking` and
|
||||
`dump.erofs --path=/inline.dat -e` to show the compressed physical extent
|
||||
inside the metadata block. Enabling the mkfs option alone does not prove
|
||||
that the target file was tail-packed.
|
||||
|
||||
## Test Steps
|
||||
1. Mount the image:
|
||||
```
|
||||
mount -t erofs /dev/md0 /mnt/test
|
||||
```
|
||||
|
||||
2. Read file with packed tail:
|
||||
```
|
||||
cat /mnt/test/inline.dat > /tmp/output.dat
|
||||
```
|
||||
|
||||
3. Verify file size correct:
|
||||
```
|
||||
stat -f %z /mnt/test/inline.dat
|
||||
```
|
||||
|
||||
4. Read file tail specifically:
|
||||
```
|
||||
tail -c 1024 /mnt/test/inline.dat > /tmp/tail.dat
|
||||
```
|
||||
|
||||
5. Verify data integrity:
|
||||
```
|
||||
sha256 /tmp/output.dat
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
- Step 2: File read successfully with tail decompressed
|
||||
- Step 3: Size matches original uncompressed size
|
||||
- Step 4: Tail data correct
|
||||
- Step 5: Checksum matches reference
|
||||
|
||||
## Verification Method
|
||||
- Verify tail-packed data decompressed correctly
|
||||
- Confirm storage efficiency (tail stored inline or in special area)
|
||||
- Test tail packing transparent to reader
|
||||
- Verify boundary between main data and packed tail handled correctly
|
||||
|
||||
## Cleanup
|
||||
```
|
||||
umount /mnt/test
|
||||
mdconfig -d -u md0
|
||||
rm /tmp/output.dat /tmp/tail.dat
|
||||
```
|
||||
|
||||
## Notes
|
||||
- ztailpacking stores compressed file tail inline with inode or in special area
|
||||
- Reduces fragmentation and improves small file efficiency
|
||||
- Related tests: TC092 (edge cases), TC033 (uncompressed tailpacking)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user