test code v1
This commit is contained in:
@@ -1,90 +0,0 @@
|
|||||||
# EROFS for FreeBSD
|
|
||||||
|
|
||||||
## Build Kernel Module
|
|
||||||
|
|
||||||
Build on FreeBSD 15 amd64 with a matching FreeBSD source tree. The default
|
|
||||||
source path is `/usr/src`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
WITH_ZSTDIO=0 ./build.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `FREEBSD_SRC=/path/to/freebsd-src` when the source tree is elsewhere. The
|
|
||||||
script is a native FreeBSD wrapper around `src/Makefile` and `bsd.kmod.mk`; the
|
|
||||||
Makefile is the authoritative module name, source list, architecture gate, and
|
|
||||||
per-source flag definition. Each run rebuilds `build/obj` and writes
|
|
||||||
`build/erofs.ko`.
|
|
||||||
|
|
||||||
Only `MACHINE_ARCH=amd64` is currently qualified. Other architectures are
|
|
||||||
rejected explicitly instead of inheriting amd64 ABI flags. Build ZSTD support
|
|
||||||
with:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
WITH_ZSTDIO=1 ./build.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
The enabled module references the FreeBSD kernel ZSTD API and therefore
|
|
||||||
requires a running kernel built with `options ZSTDIO`. `WITH_ZSTDIO=0` builds a
|
|
||||||
module without those references and rejects ZSTD-compressed images at mount.
|
|
||||||
|
|
||||||
## Mount
|
|
||||||
|
|
||||||
EROFS is read-only. Mount a single-device image with:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
mount -t erofs -o ro /dev/md0 /mnt/erofs
|
|
||||||
```
|
|
||||||
|
|
||||||
For an image with external blob devices, map every one-based on-disk device
|
|
||||||
slot explicitly with `device.<slot>=<provider>`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
mount -t erofs -o ro \
|
|
||||||
-o device.2=/dev/md92 \
|
|
||||||
-o device.1=/dev/md91 \
|
|
||||||
/dev/md90 /mnt/erofs
|
|
||||||
```
|
|
||||||
|
|
||||||
Slot names make the mapping independent of option order. Every external slot
|
|
||||||
must be present exactly once; assigning the same GEOM provider to multiple
|
|
||||||
slots is rejected. The same names and values may be passed directly as
|
|
||||||
`nmount(2)` iovec entries.
|
|
||||||
|
|
||||||
There is no repo-local `mount_erofs` binary; FreeBSD's generic `/sbin/mount`
|
|
||||||
frontend passes these distinct option names through to `nmount(2)`. The driver
|
|
||||||
forces every successful mount read-only, so even `-o rw` produces a read-only
|
|
||||||
mount rather than enabling writes.
|
|
||||||
|
|
||||||
If an image has a device table but no `device.<slot>` options are supplied,
|
|
||||||
the primary provider is treated as a Linux-compatible flatdev image. It must
|
|
||||||
contain the external ranges at their declared `uniaddr` block offsets, for
|
|
||||||
example a deterministic concatenation of the primary image and its blobs.
|
|
||||||
|
|
||||||
## Qualified Semantics
|
|
||||||
|
|
||||||
- Compact/extended metadata, Linux device-number decode, plain/inline/chunk
|
|
||||||
data, and LZ4/MicroLZMA/DEFLATE/ZSTD compressed reads.
|
|
||||||
- Inline tails are confined to the inode metadata block and declared image or
|
|
||||||
metabox backing bounds.
|
|
||||||
- Directory lookup/readdir share strict validation while accepting Linux-style
|
|
||||||
nonzero unused bytes after the final name NUL.
|
|
||||||
- Compressed `st_blocks` reflects the inode's on-disk compressed block count;
|
|
||||||
uncompressed and chunk files retain logical block rounding.
|
|
||||||
- FreeBSD 15 local vnode pager sync/async entry points are used for real mmap
|
|
||||||
faults.
|
|
||||||
- NFS export uses full 64-bit NIDs and a generation derived from the
|
|
||||||
superblock seed and inode metadata. Replacing metadata changes the generation
|
|
||||||
and makes old handles stale; a metadata-identical, payload-only replacement
|
|
||||||
is not guaranteed to return `ESTALE`.
|
|
||||||
|
|
||||||
See `docs/features.md` for the bounded feature claim and
|
|
||||||
`tests/results/manual/2026-08-09T1804Z-final-review-independent/manual-test-report.md`
|
|
||||||
for the final-review evidence.
|
|
||||||
|
|
||||||
## Test Fixtures
|
|
||||||
|
|
||||||
`tests/prepare_directory_fixtures.sh` creates the deterministic TC048/141/148
|
|
||||||
directory fixtures. `tests/prepare_error_fixtures.sh` and
|
|
||||||
`tests/erofs_fixture.py` create and self-check the structured TC002/086/087/102
|
|
||||||
and TC112-TC116/119 fixtures. Generated trees, images, overlays, and `build/`
|
|
||||||
outputs are test artifacts and are not committed.
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
|
||||||
FREEBSD_SRC="${FREEBSD_SRC:-/usr/src}"
|
|
||||||
FS_SRC="${SCRIPT_DIR}/src"
|
|
||||||
BUILD_DIR="${SCRIPT_DIR}/build"
|
|
||||||
WORK_DIR="${BUILD_DIR}/obj"
|
|
||||||
MAKE="${MAKE:-make}"
|
|
||||||
WITH_ZSTDIO="${WITH_ZSTDIO:-0}"
|
|
||||||
NM_UNDEF=""
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
[ -z "${NM_UNDEF}" ] || rm -f "${NM_UNDEF}"
|
|
||||||
}
|
|
||||||
|
|
||||||
trap cleanup EXIT
|
|
||||||
trap 'cleanup; exit 1' HUP INT TERM
|
|
||||||
|
|
||||||
fail() {
|
|
||||||
echo "ERROR: $*" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
make_kmod() {
|
|
||||||
MAKEOBJDIR="${WORK_DIR}" "${MAKE}" -C "${FS_SRC}" \
|
|
||||||
SRCTOP="${FREEBSD_SRC}" SYSDIR="${FREEBSD_SRC}/sys" \
|
|
||||||
WITH_ZSTDIO="${WITH_ZSTDIO}" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
[ "$(uname -s)" = "FreeBSD" ] ||
|
|
||||||
fail "build.sh requires a native FreeBSD build host"
|
|
||||||
[ -d "${FREEBSD_SRC}/sys" ] ||
|
|
||||||
fail "FreeBSD source tree not found: ${FREEBSD_SRC}"
|
|
||||||
[ -d "${FS_SRC}" ] || fail "Source directory not found: ${FS_SRC}"
|
|
||||||
command -v "${MAKE}" >/dev/null 2>&1 || fail "make is required"
|
|
||||||
command -v awk >/dev/null 2>&1 || fail "awk is required"
|
|
||||||
command -v nm >/dev/null 2>&1 || fail "nm is required"
|
|
||||||
[ -f "${FREEBSD_SRC}/sys/tools/vnode_if.awk" ] ||
|
|
||||||
fail "vnode_if.awk not found in ${FREEBSD_SRC}"
|
|
||||||
[ -f "${FREEBSD_SRC}/sys/kern/vnode_if.src" ] ||
|
|
||||||
fail "vnode_if.src not found in ${FREEBSD_SRC}"
|
|
||||||
case "${WITH_ZSTDIO}" in
|
|
||||||
0|1) ;;
|
|
||||||
*) fail "WITH_ZSTDIO must be 0 or 1" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
rm -rf "${WORK_DIR}"
|
|
||||||
mkdir -p "${WORK_DIR}"
|
|
||||||
KMOD="$(make_kmod -V PROG)"
|
|
||||||
[ -n "${KMOD}" ] || fail "src/Makefile did not define a module output"
|
|
||||||
|
|
||||||
echo "==> Building repo22 ${KMOD}"
|
|
||||||
make_kmod all
|
|
||||||
|
|
||||||
[ -f "${WORK_DIR}/${KMOD}" ] || fail "module was not produced"
|
|
||||||
|
|
||||||
NM_UNDEF="$(mktemp "${WORK_DIR}/nm-undef.XXXXXX")" ||
|
|
||||||
fail "could not create nm output file"
|
|
||||||
if ! nm -u "${WORK_DIR}/${KMOD}" >"${NM_UNDEF}"; then
|
|
||||||
fail "nm failed while checking ${KMOD}"
|
|
||||||
fi
|
|
||||||
if ! awk '$NF == "bcmp" { found = 1 } END { exit found }' "${NM_UNDEF}"; then
|
|
||||||
fail "${KMOD} contains an unresolved bcmp reference"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cp -f "${WORK_DIR}/${KMOD}" "${BUILD_DIR}/"
|
|
||||||
echo "==> SUCCESS: ${BUILD_DIR}/${KMOD}"
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# repo22 当前状态报告索引
|
|
||||||
|
|
||||||
- [report-1](report-1/README.md):第一次总体进度报告,保留
|
|
||||||
`573aaab7ee0b47cb6aed7f76c52c68dd4041326b` 创建时的原始内容。
|
|
||||||
- [report-2](report-2/README.md):第二次总体进度报告,按
|
|
||||||
`381349b3847209a67d669264ac54a50a3599915c` 快照汇总正式批次、动态结果、
|
|
||||||
issue、风险和下一步。
|
|
||||||
- [report-3](report-3/README.md):第三次总体进度报告,以
|
|
||||||
`12351cbb0a593474f4fcef68ffc5218d9c99dd46` 为最终验证快照,汇总完成项、
|
|
||||||
160 PASS/1 PARTIAL、独立审查结论、剩余搁置项和后续可选计划。
|
|
||||||
|
|
||||||
后续总体状态报告统一使用 `current/report-N/` 目录。逐项动态证据位于
|
|
||||||
`tests/results/manual/`,问题触发、分析和解决状态位于 `issues/`。
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
# repo22 当前总体进度
|
|
||||||
|
|
||||||
更新时间:2026-08-09 UTC
|
|
||||||
|
|
||||||
状态报告代码基线:`cd0e985b5ac54a4b7acb7042422329ad1729fb3e`
|
|
||||||
|
|
||||||
本报告记录的是上述基线上的阶段性状态。测试结果、问题状态和统计会随后续
|
|
||||||
提交继续更新,不能将本文视为 TC001-TC156 已完成全量回归的声明。
|
|
||||||
|
|
||||||
## 目标与执行范围
|
|
||||||
|
|
||||||
repo22 的目标是在 FreeBSD 15 amd64 上提供只读 EROFS 内核模块,并以可复现
|
|
||||||
fixture、真实 KLD、真实 mount/read/errno 和完整清理证据验证声明的功能边界。
|
|
||||||
|
|
||||||
当前执行约束如下:
|
|
||||||
|
|
||||||
- 只修改和提交 `repo-community/repo22`,fixture、VM overlay、KLD 和原始日志仅
|
|
||||||
放在 `/work/build` 或 guest 临时目录。
|
|
||||||
- 不建设或使用 CI、runner、自动 PASS wrapper;每个 TC 必须逐份对照对应
|
|
||||||
Markdown 手工执行。
|
|
||||||
- host 侧 `mkfs.erofs`、`dump.erofs`、`fsck.erofs` 和静态源码审查只作为 fixture
|
|
||||||
或分析证据,不能替代 FreeBSD 内核动态结果。
|
|
||||||
- 每批测试形成独立 manual report,记录 commit、构建配置、KLD SHA256、guest
|
|
||||||
版本、命令、可观察输出或 errno、fixture hash 和清理状态。
|
|
||||||
- 每批完成后提交并 push 到 `xdm/main`;并行批次若使远端前进,则 fetch、rebase
|
|
||||||
自己的 test-only 提交后正常 push,禁止 force push。
|
|
||||||
|
|
||||||
## 已完成实现与审查
|
|
||||||
|
|
||||||
当前源码已覆盖 superblock、compact/extended inode、plain/inline/chunk 数据、
|
|
||||||
目录/namecache、xattr/ACL/metabox、LZ4/MicroLZMA/DEFLATE/ZSTD、fragment、
|
|
||||||
multi-device、NFS export、pager 和多项 fail-closed 边界检查。功能声明的准确边界
|
|
||||||
以 `docs/features.md` 为准。
|
|
||||||
|
|
||||||
主要 feature 批次包括:
|
|
||||||
|
|
||||||
- `29a215dd`:POSIX ACL 与完整 xattr namespace 集成。
|
|
||||||
- `545d35bd`:xattr、long prefix、shared xattr 和 metabox 边界加固。
|
|
||||||
- `96e22cc`:cold nested namei 与目录结构校验修复。
|
|
||||||
- `4ef680df`、`78182686`:真实 multi-device、slot mapping、flatdev 和 extent
|
|
||||||
映射审查修复。
|
|
||||||
- `2354b448`:NFS export、稳定句柄和相关 vnode 路径。
|
|
||||||
- `c208bf1f`:压缩映射 P0 收口,包括多算法、partial reference 和 extent 路径。
|
|
||||||
- `9a3604fb`:metadata/VFS 语义收口,包括 inline bounds、special `rdev`、pager、
|
|
||||||
namei、NFS generation 和真实压缩占用统计。
|
|
||||||
|
|
||||||
关键收尾与工程对齐提交:
|
|
||||||
|
|
||||||
| Commit | 已完成内容 |
|
|
||||||
|---|---|
|
|
||||||
| `c881f656` | 修复 48-bit superblock union、`OFF_MAX`、大 hole 内存和大目录索引等最终 metadata 边界;建立 TC150-TC153 与三份未决 issue。 |
|
|
||||||
| `4d51ca9e` | 停止跟踪 `build/obj`、生成头和架构 symlink,避免构建产物进入正式提交。 |
|
|
||||||
| `89594551` | 将 KLD 构建布局、源文件命名、架构门控和 `WITH_ZSTDIO` 方式与 FreeBSD/Linux 上游职责对齐。 |
|
|
||||||
| `2f2ac5a8` | 更新 README、architecture、refactoring plan/status,使构建、BSD API 差异和功能边界与源码一致。 |
|
|
||||||
| `077b37ab` | 删除会伪造覆盖或无条件 PASS 的旧 runner/wrapper,加入字段断言的 fixture transformer 与 FreeBSD probe,修订关键 TC 文档。 |
|
|
||||||
| `cd0e985b` | 完成最终 review finding:per-inode NFS generation、显式 extent 物理地址溢出检查、compact/extended timestamp 校验,并直接动态执行 TC154-TC156。 |
|
|
||||||
|
|
||||||
上述工作也包含多轮 code review 和 style review:源文件职责、函数顺序和磁盘 ABI
|
|
||||||
尽量贴近 Linux EROFS;FreeBSD vnode、pager、NFS、GEOM 和 `dev_t` 差异采用
|
|
||||||
FreeBSD 15 原生接口;磁盘长度、加法、移位和 signed/unsigned 转换按 fail-closed
|
|
||||||
原则处理。
|
|
||||||
|
|
||||||
## 已有动态验证
|
|
||||||
|
|
||||||
`tests/results/manual/` 中保留了各 feature 在对应历史 commit 上的真实 FreeBSD 15
|
|
||||||
动态证据。它们证明对应变更批次曾执行内核路径,但不能替代当前 final source 的
|
|
||||||
TC001-TC156 全量重跑。
|
|
||||||
|
|
||||||
| 批次 | 主要动态证据 | 当前解释 |
|
|
||||||
|---|---|---|
|
|
||||||
| 压缩 | compact/full LZ4、legacy full index、partial reference、MicroLZMA、DEFLATE、ZSTD、fragment、ztailpacking 和多种边界 source/hash compare | 历史 feature 证据存在;G5/G6 尚需在本轮 exact KLD 重跑。 |
|
|
||||||
| xattr/ACL/metabox | inline/shared/long-prefix xattr、ACL、metabox carrier 和 corruption errno | 历史 feature 证据存在;G4 尚未启动。 |
|
|
||||||
| directory/namei/pager | cold nested lookup、目录 padding、special `rdev`、真实 mmap/page fault 和 inline bounds | 历史 feature 证据存在;G1/G3 将按当前文档重跑。 |
|
|
||||||
| multi-device | 外部 provider、显式 slot、flatdev、unified address、fragment 和 orphan/error 路径 | 历史 feature 证据存在;G7 尚未启动。 |
|
|
||||||
| NFS | getfh/fhopen、同镜像重挂、同 md 替换、ESTALE、background/stress cleanup | 历史 feature 证据存在;G8 尚未启动。 |
|
|
||||||
| final review | TC150-TC152 动态 PASS;TC153 明确 SHELVED | 结果来自 `c881f656` 前后的 final-review 批次,不是 156 项全量 PASS。 |
|
|
||||||
|
|
||||||
当前 final source `cd0e985b` 的直接动态证据是
|
|
||||||
`tests/results/manual/2026-08-09T0557Z-review-fixes/manual-test-report.md`:
|
|
||||||
|
|
||||||
- FreeBSD 15.0-RELEASE-p8 amd64 上 `WITH_ZSTDIO=0` KLD SHA256 为
|
|
||||||
`d6e755c7a75dd5043b603d58215ae3e7c8f29318b31dc1885aa9bb070d6e57a5`。
|
|
||||||
- `WITH_ZSTDIO=1` KLD SHA256 为
|
|
||||||
`b442f9f05af1d1a76801690c83c9a40ec6fc739adb0663e7dacaf837eeb2ecf3`。
|
|
||||||
- TC154、TC155、TC156 均在该 final source 上直接动态 PASS,分别覆盖 per-inode
|
|
||||||
NFS generation、explicit extent `pa + plen` overflow 和 inode timestamp
|
|
||||||
validation。
|
|
||||||
- 该批结束时 EROFS mount、KLD 和 md provider 均已清理。
|
|
||||||
|
|
||||||
## 本轮八组全量回归
|
|
||||||
|
|
||||||
TC 编号范围为 TC001-TC156,共 156 项。以下集合经计数检查为总数 156、重复 0、
|
|
||||||
遗漏 0。
|
|
||||||
|
|
||||||
| 组 | 精确集合 | 数量 | 当前状态 |
|
|
||||||
|---|---|---:|---|
|
|
||||||
| G1 | TC001, TC007, TC009, TC011-TC014, TC019-TC040, TC147, TC150, TC151 | 32 | 已启动;正在修订文档和确定性 fixture,尚未形成 final-source 32 项结论。 |
|
|
||||||
| G2 | TC002, TC008, TC010, TC015-TC018, TC112-TC116, TC119 | 13 | 已启动;使用独立 worktree/VM,尚未形成 13 项结论。 |
|
|
||||||
| G3 | TC041-TC066, TC141, TC148, TC149, TC153 | 30 | 未启动。 |
|
|
||||||
| G4 | TC005, TC067-TC083, TC117, TC134-TC140, TC142 | 27 | 未启动。 |
|
|
||||||
| G5 | TC003, TC084-TC092 | 10 | 未启动。 |
|
|
||||||
| G6 | TC004, TC102-TC110, TC143-TC146, TC155 | 15 | 未启动。 |
|
|
||||||
| G7 | TC006, TC093-TC101, TC118 | 11 | 未启动。 |
|
|
||||||
| G8 | TC111, TC120-TC133, TC152, TC154, TC156 | 18 | 未启动。 |
|
|
||||||
|
|
||||||
G1/G2 的“已启动”只表示执行代理、工作目录和任务集合已经建立,不表示其中任何
|
|
||||||
TC 已在本轮计为 PASS。G8 中 TC154/TC156、G6 中 TC155 虽已有 `cd0e985b` 直接
|
|
||||||
证据,仍需由对应全量组在最终统计中明确引用或按组要求重跑,不能导致重复计数。
|
|
||||||
|
|
||||||
## 已完成与未完成
|
|
||||||
|
|
||||||
已完成:
|
|
||||||
|
|
||||||
- 核心 feature 实现、针对性 code review、FreeBSD 15 API 对齐和构建布局收口。
|
|
||||||
- 多个历史 feature 批次的真实 KLD 动态验证与清理记录。
|
|
||||||
- 当前 final source 的双配置构建和 TC154-TC156 直接动态验证。
|
|
||||||
- 移除旧 CI 风格 runner/wrapper,建立“逐 Markdown 手工执行”的验收规则。
|
|
||||||
- 三项已知验证缺口均有详细 issue,没有把未执行或环境受限结果标成 PASS。
|
|
||||||
|
|
||||||
未完成:
|
|
||||||
|
|
||||||
- TC001-TC156 在同一 final-source 基线族上的八组全量手工回归与最终汇总。
|
|
||||||
- G1/G2 的文档修订、fixture 固化、exact KLD 执行、逐 TC 报告和 push。
|
|
||||||
- G3-G8 的启动、独立环境分配、执行和结果提交。
|
|
||||||
- TC010 所需 16 TiB 级合格 provider、TC153 大目录内核路径、explicit extent
|
|
||||||
mapped compressed payload 的正向 fixture。
|
|
||||||
|
|
||||||
## Issue 索引
|
|
||||||
|
|
||||||
检查时 `issues/` 只有以下三份已跟踪文档,没有未提交 issue 文件或真实 issue
|
|
||||||
改动,因此本状态提交不修改 `issues/`。
|
|
||||||
|
|
||||||
| Issue | 状态 | 影响 feature | Shelved 原因 |
|
|
||||||
|---|---|---|---|
|
|
||||||
| `issues/TC010-48bit-statfs-large-provider.md` | SHELVED - environment unavailable | 48-bit block count、primary provider size validation、`statfs(2)`/`df` 总量和 root/block union 选择 | 非零 `blocks_hi` 在 4 KiB block 下至少要求 16 TiB GEOM provider;当前 vnode md 流程没有已验证、可安全清理的合格 provider。小 provider 拒绝和 TC150 fallback 都不能替代正向结果。 |
|
|
||||||
| `issues/TC153-large-directory-block-index-validation.md` | SHELVED - kernel validation incomplete | 超大目录二分索引、cold lookup、`EINTEGRITY` 传播和 negative namecache 正确性 | 已有可复现 FLAT_PLAIN fixture,但尚未在 FreeBSD fixed/pre-fix KLD 上完成冷查找对照;host 生成和静态审查不足以计 PASS。 |
|
|
||||||
| `issues/extent-metadata-fixture-unavailable.md` | SHELVED - positive fixture unavailable | explicit compressed extent parser、4/8/16/32-byte record、物理/逻辑高位、binary search、partial reference/fragment 映射 | erofs-utils 1.8.6 和已试 1.9.3 均不生成真实 mapped explicit-record payload。TC152 hole 与 TC155 overflow 只覆盖部分 header/negative 分支,不能替代正向压缩数据读取。 |
|
|
||||||
|
|
||||||
## 风险与依赖
|
|
||||||
|
|
||||||
- 并行组共享远端 `xdm/main`,每批 push 前必须重新 fetch/rebase 并确认没有覆盖其他
|
|
||||||
组的 TC、helper、report 或 issue。
|
|
||||||
- FreeBSD VM、SSH 端口、qcow overlay、md unit 和 mount point 必须按组隔离;任何
|
|
||||||
guest 残留都会污染后续动态证据。
|
|
||||||
- erofs-utils 的格式生成能力限制 explicit extent 等正向 fixture,必要时只能使用
|
|
||||||
字段自检、CRC32C-aware 的 structured transformer,不能手工猜偏移。
|
|
||||||
- 48-bit 大 provider、memory pressure、NFS stress 和性能 TC 对环境容量及稳定性要求
|
|
||||||
较高,环境不足时必须使用 `SHELVED/ISSUE` 或 `ENVIRONMENT-UNAVAILABLE`,不能
|
|
||||||
降低判据。
|
|
||||||
- 历史报告跨多个 commit。最终统计必须只接受对应 exact KLD 的本轮动态结果,或
|
|
||||||
明确标注尚未重跑,禁止把旧 HEAD 结果直接升级为全量 PASS。
|
|
||||||
|
|
||||||
## 下一步
|
|
||||||
|
|
||||||
1. 完成 G1/G2 文档和 fixture 修订,构建各自 exact KLD,逐 TC 手工执行并提交报告。
|
|
||||||
2. 每个先完成的组 fetch/rebase 最新 `xdm/main`,严格 pathspec 提交并正常 push。
|
|
||||||
3. 启动 G3/G4,随后按环境和依赖启动 G5-G8;压缩、multi-device、NFS 使用隔离 VM。
|
|
||||||
4. 对任何 kernel behavior failure 立即停止 PASS 计数,新增或更新有事实依据的 issue。
|
|
||||||
5. 八组结束后汇总 156 项,检查总数、重复、遗漏、KLD/image/source hash 和全部清理
|
|
||||||
证据,再发布 final-source 全量结论。
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# repo22 当前状态索引
|
|
||||||
|
|
||||||
- [2026-08-09 总体进度](2026-08-09-overall-progress.md):基线
|
|
||||||
`cd0e985b5ac54a4b7acb7042422329ad1729fb3e` 上的实现、历史动态证据、八组
|
|
||||||
全量回归分工、未决 issue、风险和下一步。
|
|
||||||
|
|
||||||
此目录记录阶段性状态;测试结果会随后续 commit 更新。正式逐项证据位于
|
|
||||||
`tests/results/manual/`,未决验证缺口位于 `issues/`。
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
# repo22 第二次总体进度报告
|
|
||||||
|
|
||||||
更新时间:2026-08-09 UTC
|
|
||||||
|
|
||||||
权威统计快照:`381349b3847209a67d669264ac54a50a3599915c`
|
|
||||||
(该提交是当次 `xdm/main` 上完成 G3 报告后的快照)。
|
|
||||||
|
|
||||||
本报告只统计该快照已经提交的实现、正式批次和动态证据。TC060 源码修复与 G5
|
|
||||||
压缩回归正在并行进行,但在形成完整报告并提交前不提前计为 PASS,也不改变下述
|
|
||||||
冻结统计。
|
|
||||||
|
|
||||||
## 总体结论
|
|
||||||
|
|
||||||
- feature 实现、源码 code review、style review、FreeBSD 15 API 对齐和双配置构建
|
|
||||||
布局已经完成阶段性收口。
|
|
||||||
- 正式八组回归中,G1、G2、G3、G4 共执行 103 项:102 PASS,1 项
|
|
||||||
`TC060 KERNEL-FAIL` 正在修复。
|
|
||||||
- final review-fix 阶段还直接动态执行了 TC154-TC156,三项均 PASS。它们是三项
|
|
||||||
额外且不与前述 103 项重叠的 TC,因此当前共有 106 个不同 TC 具备动态结果,
|
|
||||||
其中 105 PASS、1 项待修。
|
|
||||||
- TC154-TC156 已分配给 G8,但先行 PASS 不能重复计入“已完成 G8”,也不能把 G8
|
|
||||||
标成已执行完毕。G8 尚有 TC111、TC131-TC133 未执行。
|
|
||||||
- TC010 与 TC153 已通过真实大 sparse provider 的 FreeBSD 内核路径验证并转为
|
|
||||||
RESOLVED。explicit extent 的 mapped compressed payload 正向 fixture 仍未获得,
|
|
||||||
对应 issue 尚未解决。
|
|
||||||
|
|
||||||
## 实现与审查
|
|
||||||
|
|
||||||
repo22 已完成以下阶段性工程工作:
|
|
||||||
|
|
||||||
- 实现并审查 superblock、compact/extended inode、plain/inline/chunk 数据、目录与
|
|
||||||
namecache、xattr/ACL/metabox、多算法压缩、fragment、multi-device、NFS export、
|
|
||||||
vnode pager 和 fail-closed 元数据边界。
|
|
||||||
- 对照 Linux EROFS 的磁盘 ABI、职责拆分和命名以降低长期维护偏差,同时保持
|
|
||||||
FreeBSD vnode、GEOM、pager、NFS、ACL 和 `dev_t` 语义为行为权威。
|
|
||||||
- 完成 overflow、长度、偏移、移位、signed/unsigned、目录大索引、48-bit union、
|
|
||||||
NFS generation、special vnode 和 timestamp 等多轮独立 code review 修复。
|
|
||||||
- 清理被跟踪的构建产物,统一 FreeBSD KLD 源文件布局、amd64 门控和
|
|
||||||
`WITH_ZSTDIO=0/1` 构建方式;当前构建仍以 kernel `-Werror` 为门槛。
|
|
||||||
- 删除会替代人工判定或无条件给出 PASS 的旧 CI 风格 runner/wrapper,保留可复现
|
|
||||||
fixture transformer 与原生 syscall/probe 工具。当前任务不实现 CI。
|
|
||||||
|
|
||||||
## 正式八组状态
|
|
||||||
|
|
||||||
八组精确集合总计 156 项,彼此无重复、无遗漏。
|
|
||||||
|
|
||||||
| 组 | 精确集合 | 数量 | 快照状态 |
|
|
||||||
|---|---|---:|---|
|
|
||||||
| G1 | TC001, TC007, TC009, TC011-TC014, TC019-TC040, TC147, TC150, TC151 | 32 | 32 PASS,正式批次完成。 |
|
|
||||||
| G2 | TC002, TC008, TC010, TC015-TC018, TC112-TC116, TC119 | 13 | 13 PASS,正式批次完成。 |
|
|
||||||
| G3 | TC041-TC066, TC141, TC148, TC149, TC152, TC153 | 31 | 31 已执行;30 PASS,TC060 KERNEL-FAIL。 |
|
|
||||||
| G4 | TC005, TC067-TC083, TC117, TC134-TC140, TC142 | 27 | 27 PASS,正式批次完成。 |
|
|
||||||
| G5 | TC003, TC004, TC084-TC092, TC102-TC110, TC143-TC146 | 24 | 压缩回归正在进行,尚无正式整组结论。 |
|
|
||||||
| G6 | TC006, TC093-TC101, TC118 | 11 | 尚未执行。 |
|
|
||||||
| G7 | TC120-TC130 | 11 | 尚未执行。 |
|
|
||||||
| G8 | TC111, TC131-TC133, TC154-TC156 | 7 | 正式整组未完成;TC154-TC156 已先行 PASS,TC111、TC131-TC133 尚未执行。 |
|
|
||||||
|
|
||||||
正式批次证据:
|
|
||||||
|
|
||||||
- [G1 报告](../../tests/results/manual/2026-08-09T0710Z-g1/manual-test-report.md)
|
|
||||||
- [G2 报告](../../tests/results/manual/2026-08-09T0710Z-g2/manual-test-report.md)
|
|
||||||
- [G3 报告](../../tests/results/manual/2026-08-09T1059Z-g3/manual-test-report.md)
|
|
||||||
- [G4 报告](../../tests/results/manual/2026-08-09T0839Z-g4/manual-test-report.md)
|
|
||||||
- [review-fix 报告](../../tests/results/manual/2026-08-09T0557Z-review-fixes/manual-test-report.md)
|
|
||||||
|
|
||||||
## 统计口径
|
|
||||||
|
|
||||||
正式批次已执行数为 `32 + 13 + 31 + 27 = 103`;PASS 数为
|
|
||||||
`32 + 13 + 30 + 27 = 102`,另有 TC060 一项 KERNEL-FAIL。
|
|
||||||
|
|
||||||
TC154-TC156 来自 review-fix 阶段的 exact-source FreeBSD 动态运行,并未包含在
|
|
||||||
G1-G4 的 103 项中。因此按“不同 TC 是否已有动态结果”计数,应增加三项,得到
|
|
||||||
106 个 TC 有动态结果、105 PASS、1 待修。按“正式组是否完成”计数时,三项仍属于
|
|
||||||
尚未完成的 G8,不能再次增加 PASS 数或宣称 G8 已完成。
|
|
||||||
|
|
||||||
## 大 Provider 验证
|
|
||||||
|
|
||||||
- TC010 使用逻辑长度 `17592193667072` 字节的 qualified sparse vnode provider,
|
|
||||||
动态挂载了 `blocks_hi=1` 的 48-bit EROFS,并验证 `df` 的 64-bit 总量无截断。
|
|
||||||
issue 已 RESOLVED。
|
|
||||||
- TC153 使用逻辑长度 `8796093091840` 字节的 sparse GEOM provider,令超大
|
|
||||||
FLAT_PLAIN 目录进入 `2147483648` 最终块索引的真实 kernel lookup 路径;固定 KLD
|
|
||||||
在 cold lookup 和 readdir 后均返回 `EINTEGRITY`,没有错误缓存为 `ENOENT`。
|
|
||||||
issue 已 RESOLVED。
|
|
||||||
- explicit extent 已动态覆盖 hole record、header 选择和部分负向分支,但仍缺少
|
|
||||||
mapped compressed payload 以及完整 record variant 的正向读取证据,不能关闭 issue。
|
|
||||||
|
|
||||||
## Issue 索引
|
|
||||||
|
|
||||||
| Issue | 当前状态 | 结论 |
|
|
||||||
|---|---|---|
|
|
||||||
| [TC060 standard pathconf](../../issues/TC060-pathconf-standard-values.md) | OPEN - KERNEL-FAIL | `_PC_NO_TRUNC` 与 `_PC_CHOWN_RESTRICTED` 返回 `EINVAL`;源码修复和复测正在进行。 |
|
|
||||||
| [TC010 48-bit statfs](../../issues/TC010-48bit-statfs-large-provider.md) | RESOLVED - qualified sparse vnode provider validated | qualified 16 TiB 级 sparse provider 已完成真实 mount/statfs/df 验证。 |
|
|
||||||
| [TC153 large directory index](../../issues/TC153-large-directory-block-index-validation.md) | RESOLVED - exact-source kernel validation passed | qualified 多 TiB sparse provider 已完成 exact-source 大索引 kernel lookup 验证。 |
|
|
||||||
| [Explicit extent fixture](../../issues/extent-metadata-fixture-unavailable.md) | SHELVED - positive fixture unavailable | issue 未解决;尚无使用 explicit-record parser 的 mapped compressed payload 正向 fixture。 |
|
|
||||||
|
|
||||||
## 当前风险
|
|
||||||
|
|
||||||
- TC060 是已确认的 FreeBSD kernel behavior failure,修复必须保持 NAME_MAX、PATH_MAX、
|
|
||||||
FILESIZEBITS、LINK_MAX、ACL 查询和未知键 errno 不回归,并完成 mount/md/KLD 清理。
|
|
||||||
- G5 同时覆盖 LZ4、MicroLZMA、DEFLATE、ZSTD、ztailpacking、partial reference、
|
|
||||||
explicit metadata 等多条压缩路径,fixture 资格和 `WITH_ZSTDIO` 配置差异仍是当前
|
|
||||||
最大执行风险。
|
|
||||||
- explicit extent 缺少上游工具可生成的 mapped positive fixture;静态 ABI 对照、
|
|
||||||
hole record 和 malformed case 不能替代真实压缩 payload 读取。
|
|
||||||
- G6 multi-device、G7 边界与压力类测试、G8 NFS/manual 页面仍需隔离 VM、精确 KLD、
|
|
||||||
direct syscall/数据比较和完整清理,历史 feature 报告不能自动升级为本轮结果。
|
|
||||||
- 并行 worktree 共享 `xdm/main`。每次 push 前必须 fetch/rebase,严格 pathspec,禁止
|
|
||||||
force push;guest mount、md、KLD 和临时 provider 残留必须清零。
|
|
||||||
|
|
||||||
## 下一步
|
|
||||||
|
|
||||||
1. 完成 TC060 根因修复,重跑全部 pathconf 键与基础 mount/read smoke,更新 issue
|
|
||||||
和 dated manual report。
|
|
||||||
2. 完成 G5 的 24 项压缩回归,提交 exact KLD、fixture hash、errno/数据比较与清理
|
|
||||||
证据。
|
|
||||||
3. 依次完成 G6 11 项、G7 11 项和 G8 剩余 TC111、TC131-TC133;在 G8 汇总中引用
|
|
||||||
或按要求复跑 TC154-TC156,但禁止重复计数。
|
|
||||||
4. 聚合 `TEST-COVERAGE-MATRIX`,审计 156 项总数、组间重复、遗漏、动态证据来源和
|
|
||||||
未解决 issue。
|
|
||||||
5. 完成最终独立 source review,检查 lock/resource/error path;执行
|
|
||||||
`WITH_ZSTDIO=0/1` 双配置 exact-source build,并做 `xdm/main`、remote/HEAD、
|
|
||||||
tracked clean 和 guest 清理的最终 audit。
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# repo22 第二次状态报告索引
|
|
||||||
|
|
||||||
- [第二次总体进度报告](2026-08-09-overall-progress.md):以
|
|
||||||
`381349b3847209a67d669264ac54a50a3599915c` 为统计快照,汇总实现与审查、
|
|
||||||
八组回归、动态结果计数、issue、风险和后续工作。
|
|
||||||
|
|
||||||
本目录只记录阶段性总体状态。各 TC 的命令、hash、errno、dmesg 和清理证据以
|
|
||||||
`tests/results/manual/` 中的对应报告为准。
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
# repo22 第三次总体进度报告
|
|
||||||
|
|
||||||
更新时间:2026-08-09 UTC
|
|
||||||
|
|
||||||
权威验证快照:`12351cbb0a593474f4fcef68ffc5218d9c99dd46`
|
|
||||||
|
|
||||||
最终源码基线:`fcc85b93d5f8fd9671686bd68bf3b086c8bd25cf`
|
|
||||||
|
|
||||||
## 总体结论
|
|
||||||
|
|
||||||
本轮要求的 feature 全面验证、FreeBSD/Linux 行为差异审查、code review 和
|
|
||||||
style/可维护性优化已经完成。161 个可执行 Markdown 测试均已执行并形成受控
|
|
||||||
手工证据,最终为 160 PASS、1 PARTIAL、0 FAIL、0 KERNEL-FAIL、0 ENV。
|
|
||||||
|
|
||||||
唯一未完全关闭的是 TC146 的 explicit compressed extent mapped-payload 正向
|
|
||||||
fixture。该问题已按用户授权详细记录并搁置,不是已观察到的 kernel failure,
|
|
||||||
也不影响其他 160 个 TC 的结论。本轮目标因此完成,剩余工作属于已批准搁置项
|
|
||||||
或后续可选增强。
|
|
||||||
|
|
||||||
CI 和自动化 kernel-test harness 不在本轮范围内,未实现也未宣称完成。
|
|
||||||
|
|
||||||
## 已完成内容
|
|
||||||
|
|
||||||
- 完成 TC001-TC161 的规格、执行报告和覆盖矩阵机械审计;TC000 只作为模板。
|
|
||||||
- G1-G8 的 156 个表格行覆盖 TC001-TC156,恰好一次,无重复、无遗漏。
|
|
||||||
- 完成 TC157-TC161 独立回归,覆盖 explicit extent 全局顺序、48-bit compressed
|
|
||||||
block count、special vnode 组合 setattr、dot-omitted `OFF_MAX` cookie 和 `nm`
|
|
||||||
失败传播。
|
|
||||||
- TC010 的 16 TiB-plus statfs、TC060 的 FreeBSD pathconf、TC153 的超大目录索引
|
|
||||||
均已动态验证并转为 RESOLVED。
|
|
||||||
- 完成 superblock、inode、data、directory/namecache、xattr/ACL/metabox、压缩、
|
|
||||||
multi-device、NFS、pager、错误路径和边界算术的多轮独立 review。
|
|
||||||
- 保留 Linux EROFS 的磁盘 ABI、命名、函数顺序和职责拆分作为维护参照,同时以
|
|
||||||
FreeBSD vnode、GEOM、pager、NFS、ACL、`dev_t` 和 errno 语义为行为权威。
|
|
||||||
- 修正 README 的 NFS stale 承诺:generation 来自 superblock seed 和 inode
|
|
||||||
metadata;metadata-identical payload-only replacement 不保证 `ESTALE`。
|
|
||||||
- 清理 repo22 内全部 ignored build/object/image/repro/Python bytecode 产物;最终
|
|
||||||
guest 的 EROFS mount、md、EROFS KLD 和 DTrace KLD 计数均为零。
|
|
||||||
|
|
||||||
## 最终验证统计
|
|
||||||
|
|
||||||
| 状态 | 数量 | 说明 |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| PASS | 160 | 具备对应 dated manual report 的 FreeBSD 15 手工证据 |
|
|
||||||
| PARTIAL | 1 | TC146;HEAD2/interlaced PASS,explicit mapped payload 未完成 |
|
|
||||||
| FAIL / KERNEL-FAIL | 0 | 无开放 kernel 行为失败 |
|
|
||||||
| ENV | 0 | 无环境阻塞 |
|
|
||||||
| SHELVED test case | 0 | TC146 的子项不另计为 TC |
|
|
||||||
|
|
||||||
G1-G8 证据来自多个源码提交,不能表述为所有旧 TC 都运行在最终 KLD 上。最终
|
|
||||||
`fcc85b93d` 基线接受了 TC157-TC161、相关回归以及双配置 build/load/mount smoke。
|
|
||||||
|
|
||||||
## 最终构建
|
|
||||||
|
|
||||||
FreeBSD 15 kernel `-Werror` 双配置均成功:
|
|
||||||
|
|
||||||
| 配置 | KLD SHA256 |
|
|
||||||
| --- | --- |
|
|
||||||
| `WITH_ZSTDIO=0` | `15fda9d334132cd81769ce4dff4f8411a6e2b4cf7531c352530d0de85f42a2d2` |
|
|
||||||
| `WITH_ZSTDIO=1` | `23782dc0ce7da188807d35020bf2d8c6044b796c5c9a8746b398ba784cd6ad4e` |
|
|
||||||
|
|
||||||
TC161 的私有 `nm` shim 正确使构建失败且不发布新 KLD;移除 shim 后使用
|
|
||||||
`/usr/bin/nm` 的正常重建 exit 0。两个最终 KLD 均完成独立加载和只读挂载 smoke。
|
|
||||||
|
|
||||||
## Code Review 结论
|
|
||||||
|
|
||||||
最终独立复核未发现 P0/P1。已修复的最后一批问题包括:
|
|
||||||
|
|
||||||
- 16/32-byte explicit extent table 全局严格顺序验证;
|
|
||||||
- extended compressed inode 的完整 48-bit `blocks_hi` 解码;
|
|
||||||
- special vnode size 与其他 setattr 字段组合时的 false success;
|
|
||||||
- dot-omitted 目录在 `OFF_MAX` 的 cookie/offset overflow;
|
|
||||||
- `build.sh` 对 `nm` 自身失败的可靠传播;
|
|
||||||
- NFS generation 文档与真实实现边界不一致。
|
|
||||||
|
|
||||||
从社区第三方维护者视角,未发现仍需消除的非必要 Linux/FreeBSD 结构、命名或
|
|
||||||
职责差异。保留的差异均来自 FreeBSD kernel API、锁、provider、pager、NFS 或
|
|
||||||
权限模型要求。
|
|
||||||
|
|
||||||
## 未完成与搁置
|
|
||||||
|
|
||||||
唯一批准搁置项是
|
|
||||||
[explicit mapped extent payload](../../issues/extent-metadata-fixture-unavailable.md):
|
|
||||||
|
|
||||||
- erofs-utils 1.8.6 不能生成或独立验证该新格式;
|
|
||||||
- 已尝试工具能力扫描、`--max-extent-bytes`、structured conversion、ABI/control
|
|
||||||
flow 对照以及多类负向 fixture;
|
|
||||||
- TC157 已证明 16/32-byte unordered table fail closed,但不能替代 mapped payload
|
|
||||||
的 source-identical 正向读取;
|
|
||||||
- 首个非零 `lstart` 和极大 extent-count 性能边界也保留为可选覆盖风险。
|
|
||||||
|
|
||||||
## 后续执行计划
|
|
||||||
|
|
||||||
1. 等待可生成并独立验证 explicit mapped-payload 的上游工具或可信 fixture。
|
|
||||||
2. 获得 fixture 后补充 4/8/16/32-byte 正向 record、partial reference、high words、
|
|
||||||
binary-search transition 和 final fragment 动态覆盖,使 TC146 从 PARTIAL 转 PASS。
|
|
||||||
3. 如后续项目另行启动 CI,再基于现有 Markdown 断言设计自动化;不得把当前手工
|
|
||||||
PASS 记录直接转换成无条件自动 PASS。
|
|
||||||
4. 后续源码变更继续执行受影响 TC、双配置 build、module smoke、scoped Git hygiene
|
|
||||||
和独立 review,不要求无差别重跑与改动无关的全部历史环境。
|
|
||||||
|
|
||||||
## 相关提交
|
|
||||||
|
|
||||||
正式八组手工验证:
|
|
||||||
|
|
||||||
- G1 `9ae22009f23a65320730072a780998e80aa9b728`
|
|
||||||
- G2 `aed7b68b79a5bd4115913f8361821c86fd58d2e2`
|
|
||||||
- G3 `381349b3847209a67d669264ac54a50a3599915c`
|
|
||||||
- G4 `f383bbbbff301a6bde18894f03ab88a8c0cc885a`
|
|
||||||
- G5 `c566d8ac6bf8e801082bbccf108451f6ee46ad40`
|
|
||||||
- G6 `f11fff5b8e8050e1017ed86f0bcf71042b2b45aa`
|
|
||||||
- G7 `f3ab2096fea3942317deb83fa051c84d3c124ec2`
|
|
||||||
- G8 `6f336d0a7387c8f110b19abad6e96f3ea17dba2e`
|
|
||||||
|
|
||||||
最终源码与验证收口:
|
|
||||||
|
|
||||||
- `f27b524a35b1c960be7e81884f9b928d9ac907e9`:metadata boundary 修复。
|
|
||||||
- `67d3c057fbcad5adc765ab9927da511e3221ac8f`:explicit extent header 解码修复。
|
|
||||||
- `fcc85b93d5f8fd9671686bd68bf3b086c8bd25cf`:TC157-TC161 规格与 helper。
|
|
||||||
- `12351cbb0a593474f4fcef68ffc5218d9c99dd46`:最终手工报告、覆盖、issue 和 README 汇总。
|
|
||||||
|
|
||||||
逐项证据见
|
|
||||||
`tests/results/manual/2026-08-09T1804Z-final-review-independent/manual-test-report.md`;
|
|
||||||
最终统计口径见 `docs/TEST_REPORT.md` 和 `tests/TEST-COVERAGE-MATRIX.md`。
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# repo22 第三次状态报告索引
|
|
||||||
|
|
||||||
- [第三次总体进度报告](2026-08-09-overall-progress.md):以
|
|
||||||
`12351cbb0a593474f4fcef68ffc5218d9c99dd46` 为最终验证快照,汇总已完成
|
|
||||||
feature 验证、code/style review、最终构建、剩余风险和后续计划。
|
|
||||||
|
|
||||||
本目录只记录本轮收尾状态。逐项命令、hash、errno 和清理证据以
|
|
||||||
`tests/results/manual/` 为准,issue 的触发、分析、尝试和验收条件以
|
|
||||||
`issues/` 为准。report-1 和 report-2 保留为历史快照,不因本报告改写。
|
|
||||||
@@ -1,726 +0,0 @@
|
|||||||
# repo22 任务 2:全面代码审查与风格优化评估
|
|
||||||
|
|
||||||
日期:2026-08-10
|
|
||||||
|
|
||||||
性质:只读评估,不含源码修改、测试实现或 CI 变更
|
|
||||||
|
|
||||||
范围:原任务中的“2. 进行全面的 code review 和 style 优化”
|
|
||||||
|
|
||||||
## 1. 执行结论
|
|
||||||
|
|
||||||
本轮以第三方社区维护者视角,对 repo22 的 FreeBSD EROFS 实现进行了新的严格
|
|
||||||
静态审查。审查逐条回应原任务 2 的三个目标:
|
|
||||||
|
|
||||||
1. 判断实现是否合理复用 FreeBSD kernel 已有能力,是否存在不必要的重写,或
|
|
||||||
反过来存在不应强行引用内核实现的场景。
|
|
||||||
2. 判断 BSD 与 Linux 的行为差异是否被正确识别,避免把 Linux 共同缺陷误记为
|
|
||||||
BSD 移植差异,也避免为追求外观一致而破坏 FreeBSD VFS、GEOM 和 errno 契约。
|
|
||||||
3. 判断两个独立仓库在文件职责、函数和变量命名、定义顺序、磁盘 ABI、注释和
|
|
||||||
style 上是否已经消除非必要差异。
|
|
||||||
|
|
||||||
结论是:repo22 的 FreeBSD API 集成和核心算法映射已有良好基础,但任务 2 尚不
|
|
||||||
能认定为全面完成。本轮确认:
|
|
||||||
|
|
||||||
| 等级 | 数量 | 结论 |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| P0 | 0 | 未发现当前静态证据可确认的立即阻断问题 |
|
|
||||||
| P1 | 2 | vnode 生命周期 UAF;未压缩 physical run/chunk 大读的巨型分配与 `uiomove()` 长度截断 |
|
|
||||||
| P2 | 4 | 目录排序、根类型、compact 加法回绕、explicit extent 首次全表扫描 |
|
|
||||||
| P3 | 6 | errno、时间、symlink、48-bit 边界、setattr、FRAGMENTS 注释/死分支 |
|
|
||||||
|
|
||||||
这些新 finding 均未在本轮动态复现,也未修复。本报告给出的测试均是后续建议,
|
|
||||||
不是已执行结果。CI 明确不在本轮范围。
|
|
||||||
|
|
||||||
任务 1 已完成的 feature 验证和手工测试记录不在本报告中重写。静态审查发现的
|
|
||||||
新风险也不应被误读为已推翻全部既有功能证据;它们需要后续按优先级复现、修复
|
|
||||||
并回归。
|
|
||||||
|
|
||||||
## 2. 审计方法与限制
|
|
||||||
|
|
||||||
### 2.1 方法
|
|
||||||
|
|
||||||
本轮采用以下互相独立的证据层:
|
|
||||||
|
|
||||||
- **源码静态比对**:逐文件映射 repo22 与 Linux 7.1.0-rc1 `fs/erofs`,比较磁盘
|
|
||||||
ABI、核心算法、函数职责、函数顺序和命名。
|
|
||||||
- **FreeBSD 契约核对**:直接检查 FreeBSD 15.0-RELEASE-p9 中 vnode、VFS、GEOM、
|
|
||||||
`uio`、pager、ACL、extattr、XZ、ZSTD 和参考文件系统实现。
|
|
||||||
- **历史检查**:确认 repo22 最终源码提交、Linux 参考导入提交、tree hash、历史
|
|
||||||
测试入口和 UDF helper 的可追溯程度。
|
|
||||||
- **机械检查**:执行 FreeBSD `checkstyle9.pl`,检查文件树、共同编译单元顺序、
|
|
||||||
死声明、硬编码旧目录和许可证标识。
|
|
||||||
- **独立复核**:对高风险 vnode 生命周期、目录排序、根类型、只读 `setattr`、
|
|
||||||
许可证措辞、UDF 来源措辞、旧测试入口和 style 统计进行了二次静态复核。
|
|
||||||
|
|
||||||
### 2.2 限制
|
|
||||||
|
|
||||||
- 本轮没有启动新的 FreeBSD 动态测试批次。
|
|
||||||
- 新 finding 尚未通过 fault injection、损坏镜像、并发卸载或大 I/O 实测。
|
|
||||||
- 性能风险只根据分配和扫描路径分析,未给出吞吐、延迟或内存峰值数据。
|
|
||||||
- 许可证部分只陈述仓库可观察事实,不作法律结论。
|
|
||||||
- Linux 与 FreeBSD 是独立仓库;本报告只要求维护者可识别的相似性,不要求共享
|
|
||||||
Git 历史、构建系统或平台抽象。
|
|
||||||
- `checkstyle9.pl` 自身标记部分规则为 experimental,因此输出是审查输入,不能
|
|
||||||
自动等同为每一项都必须修改。
|
|
||||||
|
|
||||||
## 3. 可复现基线
|
|
||||||
|
|
||||||
### 3.1 BSD 目标
|
|
||||||
|
|
||||||
- repo22 HEAD:`76cfb553e0951b428f9d426933a10d1fe18d2a0e`
|
|
||||||
- 最终源码变更提交:`67d3c057fbcad5adc765ab9927da511e3221ac8f`
|
|
||||||
- 当前 `src/` tree:`a605af0f01f83d67c199005e775e1a47a1610036`
|
|
||||||
- 从 `67d3c057f` 到本报告基线 HEAD,`src/` tree 未再变化。
|
|
||||||
|
|
||||||
### 3.2 Linux 独立参考
|
|
||||||
|
|
||||||
- 精简参考:`/work/dev-src-linux/fs/erofs`
|
|
||||||
- 版本:Linux 7.1.0-rc1
|
|
||||||
- 本地导入提交:`8be2be573d2b191c83d760b65c554f78eb95893c`
|
|
||||||
- EROFS tree:`b79b9a8b62f633e887a8b99075ff9412fabd7f83`
|
|
||||||
- `/work/linux-src/fs/erofs` 与精简参考内容及 tree hash 相同。
|
|
||||||
|
|
||||||
该 Linux 树只作为独立源码参考,不要求与 repo22 共仓。当前 `/work` 开发环境内
|
|
||||||
可以用提交和 tree hash 验证其身份;只获得独立 repo22 的社区维护者,则无法从
|
|
||||||
现有 repo22 文档唯一重建该基线,详见第 10 节。
|
|
||||||
|
|
||||||
### 3.3 FreeBSD API 参考
|
|
||||||
|
|
||||||
- 路径:`/work/dev-freebsd-releng`
|
|
||||||
- 版本:FreeBSD 15.0-RELEASE-p9
|
|
||||||
- 重点契约:`insmntque()`、`uiomove()`、`vfs_read_dirent()`、GEOM VFS、vnode pager、
|
|
||||||
POSIX.1e ACL、extattr、XZ Embedded、ZSTDIO 和参考文件系统。
|
|
||||||
|
|
||||||
### 3.4 提交卫生
|
|
||||||
|
|
||||||
创建 report-4 前,repo22 scoped tracked、staged、untracked 状态均为 0,且
|
|
||||||
`HEAD == xdm/main`。本次提交范围限定为 `current/report-4/`,不会修改既有源码、
|
|
||||||
测试、文档、issues、report-1 至 report-3 或 `current/README.md`。
|
|
||||||
|
|
||||||
## 4. 文件职责映射
|
|
||||||
|
|
||||||
### 4.1 共同或语义对应文件
|
|
||||||
|
|
||||||
| repo22 | Linux `fs/erofs` | 维护者视角结论 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `src/erofs_fs.h` | `erofs_fs.h` | 磁盘 ABI 应最严格对齐;字段布局正确性优先于平台风格 |
|
|
||||||
| `src/internal.h` | `internal.h`, `compress.h` | 内存结构和接口语义对应,FreeBSD 类型必然不同 |
|
|
||||||
| `src/super.c` | `super.c` | superblock、设备表、mount、statfs、生命周期 |
|
|
||||||
| `src/inode.c` | `inode.c` | inode 解码;Linux inode ops 由 BSD vnops 分担 |
|
|
||||||
| `src/data.c` | `data.c` | block/chunk mapping 对应;folio/iomap 改为 buffer/GEOM/uio |
|
|
||||||
| `src/dir.c` | `dir.c` | 目录结构解析对应;cookie 和 dirent 输出是 BSD 适配 |
|
|
||||||
| `src/namei.c` | `namei.c` | 两级二分搜索语义高度对应;namecache/锁为 BSD 适配 |
|
|
||||||
| `src/xattr.c` | `xattr.c` | 磁盘 xattr 解析对应;namespace、ACL、extattr API 不同 |
|
|
||||||
| `src/xattr.h` | `xattr.h` | 只应保留 FreeBSD 实际接口,当前仍有 Linux 残片 |
|
|
||||||
| `src/decompressor.c` | `decompressor.c` | dispatcher 对应;配置职责仍有非必要差异 |
|
|
||||||
| `src/decompressor_lzma.c` | `decompressor_lzma.c` | 算法对应;FreeBSD 侧私有嵌入 XZ Embedded |
|
|
||||||
| `src/decompressor_deflate.c` | `decompressor_deflate.c` | 直接调用 FreeBSD zlib,方向正确 |
|
|
||||||
| `src/decompressor_zstd.c` | `decompressor_zstd.c` | 使用内核 ZSTDIO,方向正确 |
|
|
||||||
| `src/zmap.c` | `zmap.c` | 压缩映射核心最接近 Linux,函数顺序对齐质量高 |
|
|
||||||
| `src/zdata.c` | `zdata.c` | 职责对应;同步读取与 Linux folio/pcluster pipeline 必然不同 |
|
|
||||||
| `src/Makefile` | `Makefile`, `Kconfig` | 只比较编译单元职责和顺序,不比较构建语法 |
|
|
||||||
|
|
||||||
### 4.2 Linux-only 文件,不应为了外观模拟
|
|
||||||
|
|
||||||
| Linux-only 文件 | 不在 repo22 创建空文件的理由 |
|
|
||||||
| --- | --- |
|
|
||||||
| `sysfs.c` | FreeBSD 无 Linux sysfs 模型,mount/sysctl 语义需独立设计 |
|
|
||||||
| `fileio.c` | Linux file-backed I/O 路径与当前 GEOM provider 模型不同 |
|
|
||||||
| `fscache.c` | Linux fscache/netfs 子系统在 FreeBSD 无直接对应 |
|
|
||||||
| `ishare.c` | Linux inode/xattr sharing 生命周期依赖其 VFS 内部模型 |
|
|
||||||
| `zutil.c` | Linux folio、bio、pcluster 工具层不适用于同步 BSD 读取路径 |
|
|
||||||
| `decompressor_crypto.c` | Linux Crypto API 后端在当前 FreeBSD 目标中无对应承诺 |
|
|
||||||
| `compress.h` | Linux 压缩调度、folio 和 stream 数据结构不能机械复制 |
|
|
||||||
|
|
||||||
缺少这些文件是必要平台差异,不是结构欠缺。为了目录看起来相同而新增空壳,会
|
|
||||||
制造虚假维护入口。
|
|
||||||
|
|
||||||
### 4.3 BSD-only 文件
|
|
||||||
|
|
||||||
| BSD-only 文件 | 必要性结论 |
|
|
||||||
| --- | --- |
|
|
||||||
| `src/erofs_vnops.c` | 必要。集中实现 VOP、pager、ACL、NFS file handle 和只读语义 |
|
|
||||||
| `src/lz4.c` | 必要。FreeBSD/OpenZFS LZ4 接口不匹配 EROFS raw block 和 partial 输出 |
|
|
||||||
| `src/erofs_defs.h` | 文件本身可存在,但当前含部分仅定义未使用的宏,必要性需缩减 |
|
|
||||||
|
|
||||||
## 5. Findings First
|
|
||||||
|
|
||||||
以下只列入已经过独立静态复核、或任务指定为已复核的结论。每项明确其类别,
|
|
||||||
避免把 Linux 共同问题写成 BSD 行为差异。
|
|
||||||
|
|
||||||
### 5.1 P0
|
|
||||||
|
|
||||||
无。
|
|
||||||
|
|
||||||
### 5.2 P1-1:`insmntque()` 失败后继续访问已回收 vnode
|
|
||||||
|
|
||||||
- **位置**:`src/inode.c:452` 调用 `insmntque()`;失败分支在
|
|
||||||
`src/inode.c:453-457` 释放 `en` 后又于 `src/inode.c:455` 写
|
|
||||||
`vp->v_data = NULL`。
|
|
||||||
- **FreeBSD 对照**:`sys/kern/vfs_subr.c:2303-2315` 在插入失败时清空
|
|
||||||
`v_data`、切换 dead ops、执行 `vgone()` 和 `vput()`;
|
|
||||||
`sys/kern/vfs_subr.c:2328-2341` 明确说明 `insmntque()` 会在失败时回收 vnode,
|
|
||||||
只有 `insmntque1()` 把清理留给调用者。
|
|
||||||
- **参考实现**:`sys/fs/cd9660/cd9660_vfsops.c:717-721` 失败后只释放私有
|
|
||||||
inode,不再解引用 vnode。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/inode.c` 使用 `iget5_locked()` /
|
|
||||||
`iget_failed()` 管理不同的 inode 生命周期,不能机械复制,但同样要求失败路径
|
|
||||||
不访问已交还对象。
|
|
||||||
- **触发与影响**:vnode 构造与强制或并发卸载竞争,进入
|
|
||||||
`MNTK_UNMOUNT`/`MNTK_UNMOUNTF` 失败路径。后续写可能成为释放后访问,并可能
|
|
||||||
清空已经复用 vnode 的 `v_data`,属于内核内存安全风险。
|
|
||||||
- **类别**:BSD 独有缺陷,源于 FreeBSD vnode 所有权契约。
|
|
||||||
- **修复方向**:采用 cd9660 所示所有权模式,失败后释放私有 `en`、清空输出并
|
|
||||||
返回,不再访问 `vp`。是否改用 `insmntque1()` 必须有明确的完整清理理由。
|
|
||||||
- **建议 Markdown 手工测试**:新增并发冷 lookup/getfh 与 `umount -f` 测试,
|
|
||||||
配合 vnode 分配压力;在 INVARIANTS/WITNESS 内核下记录 panic、WITNESS、引用
|
|
||||||
计数和清理状态。建议增加仅测试用故障注入以确定性触发插入失败。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.3 P1-2:一般未压缩 physical run/chunk 大读可触发巨型 `M_WAITOK` 分配和 `uiomove()` 长度截断
|
|
||||||
|
|
||||||
- **位置**:`src/data.c:493-500` 直接从 `uio_resid` 和映射 run 计算 `want`;
|
|
||||||
`src/data.c:514-518` 把该 `size_t` 长度传入读取路径;
|
|
||||||
`src/data.c:208-245` 的 `erofs_bread_device()` 使用
|
|
||||||
`malloc(len, M_EROFS, M_WAITOK)` 分配连续缓冲;`src/data.c:521` 再把 `size_t want`
|
|
||||||
传给 `uiomove()`。
|
|
||||||
- **FreeBSD 对照**:`sys/sys/uio.h:95` 声明
|
|
||||||
`int uiomove(void *cp, int n, struct uio *uio)`。因此大于等于 2 GiB 的 `size_t`
|
|
||||||
长度在传参时不能被该接口正确表达,可能截断为负值或零值并造成错误或无进展。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/data.c` 使用 folio/iomap 分页路径,不建立与
|
|
||||||
整个用户请求同尺寸的连续内核缓冲。该差异来自 I/O 模型,但当前无界分配不是
|
|
||||||
FreeBSD 所要求的必要差异。
|
|
||||||
- **触发与影响**:恶意或异常大 chunk/run,配合大 `VOP_READ`/`uio_resid`。影响
|
|
||||||
包括用户可控的巨型 `M_WAITOK` 连续内核分配、系统内存压力、长时间阻塞,以及
|
|
||||||
大于等于 2 GiB 时 `uiomove()` 截断或循环无进展。
|
|
||||||
- **类别**:BSD 独有缺陷,属于 I/O 分块和内核 API 宽度处理问题。
|
|
||||||
- **修复方向**:把读取固定分块到同时满足 buffer cache、`INT_MAX` 和合理内存
|
|
||||||
上限的尺寸;每轮验证 `uio_resid` 或 offset 必须前进;避免按整个 run 分配。
|
|
||||||
- **建议 Markdown 手工测试**:构造超大 chunk/run 的稀疏镜像,分别测试
|
|
||||||
`INT_MAX-1`、`INT_MAX`、`INT_MAX+1` 和大于 2 GiB 请求;记录 wired memory、
|
|
||||||
malloc failure、进度、信号中断、errno 和 mount/KLD 清理。测试必须设置资源
|
|
||||||
上限,避免把宿主机作为压力目标。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.4 P2-1:目录名称排序不变量未验证
|
|
||||||
|
|
||||||
- **位置**:`src/dir.c:72-109` 校验 dirent 数量、`nameoff` 单调、名称长度和非法
|
|
||||||
`/`,但不比较相邻名称;`src/namei.c:55-100` 执行块内二分,
|
|
||||||
`src/namei.c:103-125` 开始跨块二分选择。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/erofs_fs.h:280` 记录目录项按字典序排列;
|
|
||||||
Linux `fs/erofs/namei.c:45` 起的查找同样依赖该不变量,也未做全局排序验证。
|
|
||||||
- **触发与影响**:结构合法但名称降序、重复或跨块逆序的损坏镜像。实际存在的
|
|
||||||
名称可被静默返回为 `ENOENT`,随后建立负 namecache,使错误持续存在。
|
|
||||||
- **类别**:Linux 共同依赖的格式不变量;在 repo22“损坏结构返回
|
|
||||||
`EINTEGRITY`、不得静默 miss”的更严格政策下,是 BSD 当前一致性缺口,不应
|
|
||||||
描述成 BSD/Linux 行为差异。
|
|
||||||
- **修复方向**:对不可变目录执行一次全局严格递增验证,覆盖块内、跨块和重复
|
|
||||||
名称,并缓存结果;损坏统一返回 `EINTEGRITY`,不得写入负缓存。
|
|
||||||
- **建议 Markdown 手工测试**:构造块内降序、块内重复、跨块逆序、跨块重复四类
|
|
||||||
镜像;冷 lookup、重复 lookup、readdir 和 NFS lookup 均应返回
|
|
||||||
`EINTEGRITY`,并验证 namecache 无错误负项。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.5 P2-2:根 vnode 未验证为目录
|
|
||||||
|
|
||||||
- **位置**:`src/super.c:759-768` 的 `erofs_root()` 只调用 `erofs_vget()`;
|
|
||||||
`src/inode.c:471-475` 按 inode mode 设置 vnode 类型,并仅按 NID 设置 `VV_ROOT`。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/super.c:765-774` 加载 root inode 后明确执行
|
|
||||||
`S_ISDIR()`,非目录则释放并返回 `-EINVAL`。
|
|
||||||
- **FreeBSD 对照**:VFS mount 后续不会替 EROFS 强制验证其 `VFS_ROOT()` 返回
|
|
||||||
`VDIR`,文件系统必须自行维持该不变量。
|
|
||||||
- **触发与影响**:checksum-valid、但 root inode mode 被改为普通文件、symlink
|
|
||||||
或 FIFO 的镜像可能完成挂载;挂载点后续出现 `ENOTDIR` 或异常 vnode 语义。
|
|
||||||
- **类别**:BSD 独有缺口;Linux 已显式处理。
|
|
||||||
- **修复方向**:`erofs_vget()` 成功后验证 `(*vpp)->v_type == VDIR`,失败时正确
|
|
||||||
`vput()`。errno 可对齐 Linux 使用 `EINVAL`,或按 repo22 损坏政策使用
|
|
||||||
`EINTEGRITY`,但需统一文档。
|
|
||||||
- **建议 Markdown 手工测试**:分别生成 root inode 为 VREG、VLNK、VFIFO 的
|
|
||||||
checksum-valid 镜像,验证挂载失败、errno 稳定、无 mount/md/KLD 残留。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.6 P2-3:compact index 物理块号加法先发生 32-bit 回绕
|
|
||||||
|
|
||||||
- **位置**:`src/zmap.c:267`:
|
|
||||||
`m->pblk = le32dec(...) + nblk;`。`le32dec()` 和 `nblk` 均为 32-bit 范围,表达式
|
|
||||||
在赋给 64-bit `m->pblk` 前可能已经回绕。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/zmap.c:230-232` 使用同样的
|
|
||||||
`le32_to_cpu(...) + nblk` 结构,因此 Linux 参考也存在相同风险。
|
|
||||||
- **触发与影响**:基准物理块接近 `UINT32_MAX` 且 compact 索引累计 `nblk` 非零,
|
|
||||||
映射到错误的低地址,可能读到错误数据或触发后续一致性错误。
|
|
||||||
- **类别**:Linux 共同缺陷,绝不能为了源码相似而保留,也不能记成 BSD 差异。
|
|
||||||
- **修复方向**:在加法前显式提升到 64-bit,并使用 checked addition;随后按设备
|
|
||||||
块范围验证。
|
|
||||||
- **建议 Markdown 手工测试**:构造 base pblk 接近 `UINT32_MAX`、累计跨越边界的
|
|
||||||
compact 索引,验证映射不会回绕;同时测试恰好不溢出的边界和真实设备范围错误。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.7 P2-4:explicit extent 首次初始化执行有界 O(N) 全表扫描
|
|
||||||
|
|
||||||
- **位置**:`src/zmap.c:581-619` 的 `z_erofs_validate_extent_table()` 在首次初始化
|
|
||||||
时从 `index=0` 到 `en->z_extents-1` 逐项读取并验证严格递增;调用后才进入
|
|
||||||
二分映射路径。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/zmap.c:501-588` 映射 explicit extent 时按需
|
|
||||||
二分读取,没有 repo22 这一首次完整预扫描。
|
|
||||||
- **触发与影响**:超大 extent 表在首次访问时产生 O(N) 元数据 I/O 和延迟,攻击
|
|
||||||
者可用格式边界内的大计数制造明显可用性压力。
|
|
||||||
- **边界说明**:循环由 `en->z_extents` 严格限制,记录位置使用 checked arithmetic,
|
|
||||||
并验证 `lstart` 严格递增。当前证据不支持“无限循环”或“无边界访问”的说法。
|
|
||||||
- **类别**:BSD 独有的性能/可用性权衡,源于更严格的全表不变量验证,不是立即
|
|
||||||
correctness 失败。
|
|
||||||
- **修复方向**:先量化真实最坏情况。可评估分段验证、验证结果缓存、mount-time
|
|
||||||
预算或按二分访问范围逐步验证;任何优化都不能重新引入静默错误映射。
|
|
||||||
- **建议 Markdown 手工测试**:生成多档 extent count 的合法/末尾损坏表,测量
|
|
||||||
首次与重复 lookup/read 延迟、I/O 次数和内存;验证预算超限时 errno 和清理。
|
|
||||||
- **状态**:已静态复核;未做性能原型;未修复。
|
|
||||||
|
|
||||||
### 5.8 P3-1:DEFLATE 分配失败被统一映射为 `EIO`
|
|
||||||
|
|
||||||
- **位置**:`src/decompressor.c:246-257` 将所有后端非零返回统一转换为 `EIO`;
|
|
||||||
`src/decompressor_deflate.c` 的分配失败因而不能保留 `ENOMEM`。
|
|
||||||
- **Linux/FreeBSD 对照**:平台均区分资源耗尽和输入/设备错误;调用 FreeBSD
|
|
||||||
zlib 是正确的,但 wrapper 的返回契约过窄。
|
|
||||||
- **影响**:内存压力下诊断和上层重试策略失真。
|
|
||||||
- **类别**:BSD 独有 errno 映射问题。
|
|
||||||
- **修复方向**:后端返回正 errno,dispatcher 只做必要规范化。
|
|
||||||
- **建议测试**:故障注入 DEFLATE workspace/output 分配失败,要求 `ENOMEM`;损坏
|
|
||||||
流仍应为 `EIO` 或项目约定的完整性错误。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.9 P3-2:负 Unix 时间被拒绝,和 Linux 语义不一致
|
|
||||||
|
|
||||||
- **位置**:`src/inode.c:60-68` 以 `uint64_t seconds` 接收时间,并拒绝大于
|
|
||||||
`INT64_MAX` 的值。
|
|
||||||
- **Linux 对照**:Linux `fs/erofs/inode.c:108-109` 将磁盘 extended inode 的
|
|
||||||
64-bit 时间传给 inode time;Linux 时间模型允许 1970 年前的负时间语义。
|
|
||||||
- **影响**:使用补码表达负秒值的镜像在 BSD 被视为损坏,形成跨平台兼容差异。
|
|
||||||
- **类别**:BSD/Linux 行为差异,格式签名语义需先与上游规范确认。
|
|
||||||
- **修复方向**:确认磁盘字段的正式有符号语义,再采用显式 signed 解码和 FreeBSD
|
|
||||||
`timespec` 范围检查。
|
|
||||||
- **建议测试**:覆盖 `-1`、`INT64_MIN` 邻近值、epoch 和正最大值,在 Linux/BSD
|
|
||||||
上比较 stat 结果与 errno。
|
|
||||||
- **状态**:静态候选已复核;格式语义仍需上游确认;未修复。
|
|
||||||
|
|
||||||
### 5.10 P3-3:inline symlink 未拒绝声明长度内嵌 NUL
|
|
||||||
|
|
||||||
- **位置**:`src/data.c:529-533` 的 readlink 直接复用普通读取路径;
|
|
||||||
`src/data.c:493-525` 按 inode 声明长度移动字节,没有对 symlink payload 做 NUL
|
|
||||||
一致性检查。
|
|
||||||
- **Linux 对照**:Linux 同样主要依赖 inode size 和 VFS symlink 语义;本项不是
|
|
||||||
用于制造表面差异,而是要求 BSD 明确损坏镜像政策。
|
|
||||||
- **影响**:声明长度内部出现 NUL 时,不同调用者可能观察截断或不一致目标。
|
|
||||||
- **类别**:损坏输入处理缺口,是否需要拒绝应与 EROFS 格式语义统一。
|
|
||||||
- **修复方向**:确认格式是否禁止嵌入 NUL;若禁止,在 inode/readlink 验证中返回
|
|
||||||
`EINTEGRITY`,且不得影响合法非 NUL 目标。
|
|
||||||
- **建议测试**:inline 和非 inline symlink 分别构造中间 NUL、末尾 NUL、无 NUL
|
|
||||||
目标,比较 `readlink(2)`、namei 跟随和 NFS 行为。
|
|
||||||
- **状态**:静态候选已复核;格式语义待确认;未修复。
|
|
||||||
|
|
||||||
### 5.11 P3-4:48-bit end-exclusive 检查拒绝最后一个合法完整块
|
|
||||||
|
|
||||||
- **位置**:`src/zmap.c:895-898` 计算 `pend = m_pa + m_plen`,随后以
|
|
||||||
`(pend >> block_bits) >= (1ULL << 48)` 拒绝映射。
|
|
||||||
- **Linux 对照**:Linux 参考中的相关 48-bit 映射边界也存在同类 end-exclusive
|
|
||||||
处理风险。
|
|
||||||
- **触发与影响**:映射恰好结束在 48-bit 地址空间上界时,`pend` 是合法的
|
|
||||||
end-exclusive 值,但当前检查把最后一个完整合法块拒绝为 `EINTEGRITY`。
|
|
||||||
- **类别**:Linux 共同边界缺陷,不是 BSD 差异。
|
|
||||||
- **修复方向**:校验最后一个实际字节/块,或使用 `pend > limit` 的 byte limit
|
|
||||||
比较,并单独处理零长度。
|
|
||||||
- **建议测试**:覆盖最后合法块、越界一字节、越界一块和零长度映射。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.12 P3-5:birthtime-only `VOP_SETATTR()` 可假成功
|
|
||||||
|
|
||||||
- **位置**:`src/erofs_vnops.c:252-281` 检查 mode、uid、gid、atime、mtime、flags
|
|
||||||
和 size,但不检查 `va_birthtime`,最终可能返回 0。
|
|
||||||
- **FreeBSD 对照**:`VATTR_NULL()` 会把 birthtime 设为 `VNOVAL`,内核调用者可以
|
|
||||||
构造仅 birthtime 有效的请求。
|
|
||||||
- **触发与影响**:直接内核 VOP 调用可收到成功但属性未改变,违反只读 VOP 语义。
|
|
||||||
- **路径限定**:独立复核未确认普通用户态或 NFSv4 可绕过只读 mount 检查到达该
|
|
||||||
单属性路径,因此不能声称已有用户/NFS 可利用的假成功链。
|
|
||||||
- **类别**:BSD 独有 VOP 契约和未来维护问题,严重度降为 P3。
|
|
||||||
- **修复方向**:birthtime 变更返回 `EROFS`;对 type、nlink、fsid、fileid、
|
|
||||||
blocksize、rdev、bytes、generation 等结构字段明确返回 `EINVAL`。
|
|
||||||
- **建议测试**:扩展内核 probe,直接提交 birthtime-only 和各结构字段请求;本地
|
|
||||||
syscall 与 NFS 测试用于确认它们仍被只读层拒绝。
|
|
||||||
- **状态**:已静态复核;无已证实用户/NFS 路径;未修复。
|
|
||||||
|
|
||||||
### 5.13 P3-6:FRAGMENTS 特例分支不可达,注释与支持边界失配
|
|
||||||
|
|
||||||
- **位置**:`src/erofs_fs.h:56-64` 已把 `EROFS_FEATURE_INCOMPAT_FRAGMENTS` 放入
|
|
||||||
`EROFS_ALL_SUPPORTED_INCOMPAT`;`src/super.c:532` 因而从 `unsupported` 中清除该
|
|
||||||
bit,但 `src/super.c:533-549` 又试图在 `unsupported != 0` 时特例允许仅
|
|
||||||
FRAGMENTS 的组合。
|
|
||||||
- **Linux 对照**:Linux 通过实际 fragment/packed inode 路径表达支持,不需要
|
|
||||||
这种与 supported mask 自相矛盾的特例。
|
|
||||||
- **影响**:当前分支不可达,注释声称“窄允许”但真实代码已经把 FRAGMENTS 当作
|
|
||||||
一般 supported incompat bit,误导维护者判断支持边界。
|
|
||||||
- **类别**:BSD 独有死分支和文档一致性问题。
|
|
||||||
- **修复方向**:依据真实 feature 支持政策二选一:从 supported mask 移除后保留
|
|
||||||
严格特例,或删除死分支并准确文档化支持范围。
|
|
||||||
- **建议测试**:组合测试 FRAGMENTS、XATTR_PREFIXES、PLAIN_XATTR_PFX 和
|
|
||||||
`packed_nid`,记录 mount errno 和实际 fragment inode 访问结果。
|
|
||||||
- **状态**:已静态复核;未动态复现;未修复。
|
|
||||||
|
|
||||||
### 5.14 不列为 correctness finding:fragment `pstart_hi`
|
|
||||||
|
|
||||||
曾有候选认为 fragment extent 构造会丢失 `pstart_hi`。当前静态证据不足以确认该
|
|
||||||
字段在 fragment 记录格式中具有同样的高位语义,也不足以证明当前路径实际丢失
|
|
||||||
可用地址。因此本报告不把它列为 correctness finding,只保留为“与上游格式语义
|
|
||||||
确认”的待办。后续必须先取得格式规范或上游实现证据,再决定是否测试或修改。
|
|
||||||
|
|
||||||
## 6. FreeBSD 最佳实践与原生能力复用
|
|
||||||
|
|
||||||
| 领域 | 当前做法 | 评估与决策 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| DEFLATE | `src/decompressor_deflate.c:28` 起调用 FreeBSD zlib | 正确复用;应保留,修正 errno 契约即可 |
|
|
||||||
| ZSTD | `src/decompressor_zstd.c` 使用 ZSTDIO API | 正确复用;FreeBSD 无通用独立 zstd KLD,不应伪造依赖 |
|
|
||||||
| MicroLZMA | `src/decompressor_lzma.c:14-38` 私有重命名并编译 XZ Embedded | 应保留本地实现;stock `xz.ko` 未定义 `XZ_DEC_MICROLZMA`,不能强行链接 |
|
|
||||||
| LZ4 | `src/lz4.c:21` 起实现 raw/partial decoder | 应保留;FreeBSD/OpenZFS 接口含不同 framing,且不满足 EROFS partial 语义 |
|
|
||||||
| 目录输出 | `src/dir.c:160-178` 自有 cookie helper | 不能机械替换;它额外验证 cookie 严格递增和容量短读 |
|
|
||||||
| `vfs_read_dirent()` | FreeBSD `sys/kern/vfs_subr.c:6814-6830` | 可原型化为输出层 helper,但必须保留 EROFS cookie 约束并回归 NFS |
|
|
||||||
| GEOM/VFS I/O | `src/super.c:226` 建 consumer,`src/data.c:250` 用 `bread()` | 符合 FreeBSD 文件系统惯用路径,不应改为 GEOM class 私有读接口 |
|
|
||||||
| vnode cache | `src/inode.c:435-460` 用 `vfs_hash_get/insert` | 总体正确;仅 `insmntque()` 失败所有权需修复 |
|
|
||||||
| pager | `src/erofs_vnops.c:434` 复用 local pager | 正确,避免重写 VM pager |
|
|
||||||
| ACL/extattr | `src/erofs_vnops.c:68` 等调用 POSIX.1e ACL/extattr API | 正确保留 BSD namespace 和权限差异 |
|
|
||||||
| CRC32C | `src/super.c:307` 使用 `calculate_crc32c()` | 正确复用 FreeBSD kernel helper |
|
|
||||||
| endian | 磁盘字段使用 `leXXtoh`,非对齐流使用 `leXXdec` | 正确;不应直接复制 Linux unaligned 宏 |
|
|
||||||
| checked arithmetic | 多处使用 compiler overflow builtin | 合理;FreeBSD 15 无更优的通用非 LinuxKPI 替代 |
|
|
||||||
|
|
||||||
### 6.1 为什么不能强行依赖 `xz.ko`
|
|
||||||
|
|
||||||
FreeBSD `sys/modules/xz/Makefile:5-20` 会编译 `xz_dec_lzma2.c` 并导出符号,但没有
|
|
||||||
定义 `XZ_DEC_MICROLZMA`。MicroLZMA 入口受该宏控制,因此 stock `xz.ko` 不提供
|
|
||||||
repo22 所需的 `xz_dec_microlzma_*` ABI。简单添加 `MODULE_DEPEND(erofs, xz, ...)`
|
|
||||||
不能解决符号缺失。
|
|
||||||
|
|
||||||
只有在 FreeBSD 正式启用并导出 MicroLZMA KPI,同时更新模块 ABI/version 后,
|
|
||||||
repo22 才应重新评估直接依赖。当前强行引用反而违反“优先复用,但不强制引用一切”
|
|
||||||
的原任务要求。
|
|
||||||
|
|
||||||
### 6.2 LZMA per-call allocation 是性能原型事项
|
|
||||||
|
|
||||||
`src/decompressor_lzma.c:55-66` 每次解压分配并释放 decoder state。Linux 使用可
|
|
||||||
复用 stream pool。当前没有证据证明它造成 correctness 错误,但并发压缩读取会
|
|
||||||
产生约 30 KiB state 的反复 malloc/free 和锁竞争。
|
|
||||||
|
|
||||||
后续应单独做 per-CPU、mount-local 或受限 pool 原型,测量并发吞吐、内存峰值、
|
|
||||||
卸载清理和字典变化。没有数据前,不应把缓存重构混入 correctness 批次。
|
|
||||||
|
|
||||||
## 7. BSD/Linux 行为差异分类
|
|
||||||
|
|
||||||
### 7.1 必要的 BSD 差异
|
|
||||||
|
|
||||||
- 正 errno,而不是 Linux 内核负 errno。
|
|
||||||
- VOP/VFS operation table、vnode lock、namecache、`vn_vget_ino()` 和
|
|
||||||
`vfs_hash_*` 生命周期。
|
|
||||||
- GEOM consumer、设备 vnode 和 buffer cache I/O,而不是 folio/iomap/bio。
|
|
||||||
- FreeBSD extattr user/system namespace、`extattr_check_cred()` 和 POSIX.1e ACL。
|
|
||||||
- readdir 的 `a_cookies`/`a_ncookies` ABI、synthetic dot cookie 和 NFS 恢复语义。
|
|
||||||
- `fifo_specops`、FreeBSD FID 布局、generation 与 `ESTALE` 校验。
|
|
||||||
- pager 使用 `vnode_pager_local_getpages*`。
|
|
||||||
|
|
||||||
这些差异应保留,不应为了外观接近 Linux 而移除。
|
|
||||||
|
|
||||||
### 7.2 Linux 共同缺陷
|
|
||||||
|
|
||||||
- compact index 32-bit 加法回绕,见 `src/zmap.c:267` 与 Linux
|
|
||||||
`fs/erofs/zmap.c:231`。
|
|
||||||
- 48-bit end-exclusive 最后合法块边界。
|
|
||||||
- 目录二分依赖排序;Linux 也未全局验证。repo22 可选择更严格验证,但不能把
|
|
||||||
上游共同不变量说成 BSD 偏差。
|
|
||||||
|
|
||||||
源码相似不是保留共同缺陷的理由。修复时应尽量沿用上游命名和 checked arithmetic
|
|
||||||
结构,并把可上游化的发现单独记录。
|
|
||||||
|
|
||||||
### 7.3 BSD 独有缺陷
|
|
||||||
|
|
||||||
- `insmntque()` 失败后的 vnode 释放后访问。
|
|
||||||
- chunk 大读的整段 `M_WAITOK` 分配和 `size_t` 到 `int` 的 `uiomove()` 传参。
|
|
||||||
- root vnode 未检查 `VDIR`。
|
|
||||||
- DEFLATE errno 归一化过度。
|
|
||||||
- birthtime-only `VOP_SETATTR()` 假成功。
|
|
||||||
- FRAGMENTS supported mask 与特例注释矛盾。
|
|
||||||
|
|
||||||
### 7.4 非必要维护差异
|
|
||||||
|
|
||||||
- `erofs_fs.h` 定义顺序、常量命名和字段注释没有尽量保持 Linux 顺序。
|
|
||||||
- 压缩配置 loader 集中于 `decompressor.c`,而 Linux 分布在各 backend。
|
|
||||||
- backend 函数名使用 `lzma_decompress`、`deflate_decompress`、
|
|
||||||
`zstd_decompress`,没有采用 Linux `z_erofs_*` 体系。
|
|
||||||
- `xattr.h`、`internal.h`、`erofs_defs.h` 中仍有失效 Linux 声明或未使用抽象。
|
|
||||||
- xattr prefix helper 命名、部分函数定义位置和空包装与 Linux 无必要不同。
|
|
||||||
|
|
||||||
### 7.5 需要原型或格式确认后再判断
|
|
||||||
|
|
||||||
- fragment extent 的 `pstart_hi` 语义。
|
|
||||||
- LZMA decoder state 缓存。
|
|
||||||
- 保留 cookie 验证的 `vfs_read_dirent()` 输出适配器。
|
|
||||||
- explicit extent 全表验证的分段/缓存策略。
|
|
||||||
- negative timestamp 与 inline symlink NUL 的正式格式语义。
|
|
||||||
|
|
||||||
## 8. 结构、命名和 style 对齐
|
|
||||||
|
|
||||||
### 8.1 正向对齐结果
|
|
||||||
|
|
||||||
- repo22 与 Linux 有 15 个共同 C/H 文件名。
|
|
||||||
- `src/namei.c` 的核心名称查找函数名称和顺序高度对应 Linux。
|
|
||||||
- `src/zmap.c` 的 13 个共享核心算法函数保持相同相对顺序,是当前对齐质量最高的
|
|
||||||
文件之一。
|
|
||||||
- `src/Makefile` 中 12 个共同编译单元保持与 Linux Makefile 相同的相对顺序。
|
|
||||||
- `erofs_vnops.c` 集中 BSD VOP glue,避免把 FreeBSD 代码散入所有 Linux 对应
|
|
||||||
算法文件,这一文件级差异是必要且有利于维护的。
|
|
||||||
|
|
||||||
### 8.2 `erofs_fs.h` 的非必要差异
|
|
||||||
|
|
||||||
BSD 与 Linux 都包含同一组核心磁盘结构,但 repo22 的结构顺序、常量命名和注释
|
|
||||||
存在明显漂移。例如 repo22 从 `src/erofs_fs.h:104` 定义 superblock,而 Linux
|
|
||||||
先定义 deviceslot;dirent、chunk index、map header 和 lcluster index 的位置也有
|
|
||||||
移动。机械审查对 19 个核心 struct/union 记录到 31/171 个顺序逆序对,顺序相似度
|
|
||||||
约 81.9%。
|
|
||||||
|
|
||||||
字段 packing、offset、endian 和 `_Static_assert` 是 correctness 约束,应保留 BSD
|
|
||||||
表达;结构定义顺序、字段语义注释和非平台相关名称则应尽量恢复 Linux,以降低
|
|
||||||
未来磁盘格式同步成本。`EROFS_ALL_SUPPORTED_INCOMPAT` 与 Linux 名称不同,也应
|
|
||||||
先判断是否存在真实语义差异,再决定是否保留。
|
|
||||||
|
|
||||||
### 8.3 压缩职责和命名
|
|
||||||
|
|
||||||
repo22 把 LZMA、DEFLATE、ZSTD 配置解析集中在 `src/decompressor.c`,Linux 则分别
|
|
||||||
放在对应 backend。调用 ABI 必须因 FreeBSD 内核 API 而不同,但配置 loader 的
|
|
||||||
文件职责和 `z_erofs_*` 命名并无平台限制。
|
|
||||||
|
|
||||||
建议在 correctness 修复完成后,单独评估把配置解析移回各 backend,并统一内部
|
|
||||||
命名。该重排必须保持双配置构建和全部压缩 Markdown 测试,不应与 P1/P2 修复混在
|
|
||||||
同一提交。
|
|
||||||
|
|
||||||
### 8.4 死代码和残留抽象
|
|
||||||
|
|
||||||
- `src/xattr.h:11-42` 保留注释掉的 Linux `CONFIG_*` 分支、未实现的
|
|
||||||
`erofs_xattr_handlers`、`struct inode` 和 `struct posix_acl` 声明。
|
|
||||||
- `src/internal.h:50-71` 保留未使用的同步解压/cache 枚举和 `erofs_buf`;
|
|
||||||
`src/internal.h:243-247` 的 `erofs_is_fileio_mode()` 固定返回 false。
|
|
||||||
- `src/erofs_defs.h:5-19` 的 CRC polynomial、inode slot bits 和 range-coder 常量
|
|
||||||
多项仅定义未使用;`src/inode.c:137-139` 仍直接使用字面量 5。
|
|
||||||
- `src/super.c` 的部分空包装和函数顺序可进一步与 Linux/FreeBSD 惯例收敛,但应
|
|
||||||
放在纯维护提交中。
|
|
||||||
|
|
||||||
### 8.5 失效测试入口和 harness
|
|
||||||
|
|
||||||
- `test_all_decompress.sh:2-7` 仍标记 repo19;其 `SRCDIR` 当前未实际使用,但测试
|
|
||||||
内容不验证 repo22 KLD。
|
|
||||||
- `test_chunk_based.sh:2-17` 实际进入 repo17,后续会 clean、写镜像、卸载模块、
|
|
||||||
配置 md 和 mount,具有真实误操作其他目录和全局系统状态的风险。
|
|
||||||
- `tests/test_decompress.c` 与 `tests/test_decompress_standalone.c` 已无法通过当前语法
|
|
||||||
检查,并仍按旧参数数量调用后端接口;当前接口见 `src/internal.h:314-322`。
|
|
||||||
|
|
||||||
`docs/architecture.md:242-245` 已声明这两个根脚本不能作为验收入口,但只写文档
|
|
||||||
不足以消除可执行误入口。后续应删除、移入明确的 historical 目录,或改为立即失败
|
|
||||||
并指向 `tests/TC*.md`。
|
|
||||||
|
|
||||||
### 8.6 文档陈旧
|
|
||||||
|
|
||||||
- `docs/architecture.md:79` 的 `erofs_mount` 示例与当前
|
|
||||||
`src/internal.h` 结构不一致,字段如 `z_algorithmformat`、`fragmentoff` 已陈旧。
|
|
||||||
- `docs/architecture.md:273` 声称“零拷贝”,但 `src/data.c:244-261` 明确执行
|
|
||||||
`malloc` 和 `memcpy`。
|
|
||||||
- Linux 基线只记录绝对工作区路径和版本,没有独立仓库可获取的上游 provenance。
|
|
||||||
|
|
||||||
### 8.7 style(9) 机械结果
|
|
||||||
|
|
||||||
使用 FreeBSD `tools/build/checkstyle9.pl` 0.31 对 `src/*.[ch]` 连续检查,结果稳定:
|
|
||||||
|
|
||||||
- 18 个文件;
|
|
||||||
- 48 warnings;
|
|
||||||
- 1 error;
|
|
||||||
- 44 个超过 80 列;
|
|
||||||
- 4 个块注释格式告警;
|
|
||||||
- 唯一 error:`src/erofs_fs.h:265` 的 `return 0` 缺 FreeBSD 风格括号。
|
|
||||||
|
|
||||||
其他可见项包括 `src/internal.h:11-12` 的 `sys/param.h // MUST FIRST` 实际位于
|
|
||||||
`sys/types.h` 后,SPDX 注释形式混用,以及部分 Makefile 空白不统一。
|
|
||||||
|
|
||||||
这些结果不能机械全改。磁盘 ABI 宏、静态断言和与 Linux 保持一致的行,可能有
|
|
||||||
理由超过 80 列。建议先制定“FreeBSD style(9) 优先、磁盘 ABI/上游同步可例外”的
|
|
||||||
仓库规则,再逐批清理。
|
|
||||||
|
|
||||||
## 9. 正向成果与保留项
|
|
||||||
|
|
||||||
本轮不能只列问题。以下成果符合原任务 2 的目标,应在后续优化中保留:
|
|
||||||
|
|
||||||
- 使用 `bsd.kmod.mk`,而不是维持 Linux Kbuild 兼容层。
|
|
||||||
- GEOM consumer、设备 vnode、`bread()` 和 buffer cache 的组合符合 FreeBSD 文件
|
|
||||||
系统路径。
|
|
||||||
- `vfs_hash_*`、vnode pager、ACL、extattr、CRC32C、endian helper 和 checked
|
|
||||||
arithmetic 的总体选型正确。
|
|
||||||
- DEFLATE 和 ZSTD 直接复用可用的 FreeBSD 内核实现。
|
|
||||||
- 不强行依赖缺少 MicroLZMA ABI 的 `xz.ko`,不强行套用不兼容的 OpenZFS LZ4。
|
|
||||||
- `namei.c` 和 `zmap.c` 核心函数顺序与 Linux 高度对应。
|
|
||||||
- Linux-only 文件没有以空壳方式复制到 BSD 仓库。
|
|
||||||
- FreeBSD-only VOP glue 集中在 `erofs_vnops.c`,平台边界清晰。
|
|
||||||
- 既有动态测试已覆盖多设备、压缩映射、xattr/ACL、NFS、48-bit 和边界行为;
|
|
||||||
本报告不重写这些 task 1 证据。
|
|
||||||
|
|
||||||
## 10. 可追溯性与许可证边界
|
|
||||||
|
|
||||||
### 10.1 仓库许可证材料
|
|
||||||
|
|
||||||
repo22 的 18 个生产 `src/*.[ch]` 文件均带 SPDX 标识:13 个
|
|
||||||
`GPL-2.0-only`、4 个 `BSD-2-Clause`、1 个 `MIT`。`docs/erofs.5:1-23` 自身包含
|
|
||||||
完整的 BSD 两条款文本。
|
|
||||||
|
|
||||||
但 repo22 根目录没有集中式 `LICENSE`、`COPYING`、`NOTICE`、许可证构成表或来源
|
|
||||||
清单。SPDX 可以识别文件当前声明,不能单独让第三方重建整个 KLD 的来源、整体
|
|
||||||
分发边界和权利链。
|
|
||||||
|
|
||||||
建议后续增加集中式许可证和来源 manifest,明确 GPL 派生核心、MIT 磁盘 ABI、
|
|
||||||
BSD VOP wrapper、本地 LZ4 和嵌入 XZ 源的关系。本报告不作兼容性或法律结论。
|
|
||||||
|
|
||||||
### 10.2 UDF helper 来源
|
|
||||||
|
|
||||||
`src/dir.c:158-178` 明确写有“modelled after UDF”。历史版本的 `erofs_uiodir`
|
|
||||||
与 FreeBSD `sys/fs/udf/udf_vnops.c:614-639` 在结构、分支顺序和控制流上高度接近;
|
|
||||||
当前版本已增加严格 cookie 单调性、结果枚举、容量检查和不同错误传播。
|
|
||||||
|
|
||||||
现有 Git 历史不足以区分最初是直接复制、紧密改写还是参考实现,因此不得断言
|
|
||||||
侵权或具体来源类别。应由作者确认来源过程,并据此决定是否补充 FreeBSD UDF 的
|
|
||||||
版权归属或说明。
|
|
||||||
|
|
||||||
### 10.3 Linux 基线外部可复现性
|
|
||||||
|
|
||||||
在当前 `/work` 单仓环境内,Linux 参考可由导入提交
|
|
||||||
`8be2be573d2b191c83d760b65c554f78eb95893c` 和 tree
|
|
||||||
`b79b9a8b62f633e887a8b99075ff9412fabd7f83` 验证。
|
|
||||||
|
|
||||||
`docs/architecture.md:160-163` 目前只记录本地绝对路径和 Linux 7.1-rc1 字符串,
|
|
||||||
没有官方上游 URL、上游 Git commit/tag、获取命令和校验值。因此内部审查可复现,
|
|
||||||
独立社区仓库的外部复现材料仍不完整。
|
|
||||||
|
|
||||||
## 11. 第三方维护者相似度
|
|
||||||
|
|
||||||
以下评分来自文件树、共同符号顺序、磁盘 ABI 顺序、FreeBSD API、代码卫生和文档
|
|
||||||
可复现性的综合人工/机械评估。它不是客观度量,也不代表 feature 完整度:
|
|
||||||
|
|
||||||
| 维度 | 暂评分 | 说明 |
|
|
||||||
| --- | ---: | --- |
|
|
||||||
| 文件树与职责 | 8.0/10 | 共同文件清晰,Linux-only/BSD-only 边界总体合理 |
|
|
||||||
| 核心算法命名和顺序 | 8.5/10 | namei/zmap 较好,压缩后端仍有差异 |
|
|
||||||
| 磁盘 ABI 头文件可同步性 | 6.0/10 | 布局重视正确性,但顺序、命名、注释漂移明显 |
|
|
||||||
| FreeBSD API 与构建集成 | 9.0/10 | GEOM、VFS、pager、ACL、压缩库选型总体正确 |
|
|
||||||
| 代码卫生与 style(9) | 5.5/10 | 死声明、旧入口、48 warnings/1 error |
|
|
||||||
| 社区文档与基线可复现性 | 5.0/10 | 内部可验证,独立仓库 provenance 不完整 |
|
|
||||||
| **综合维护者相似度** | **7.2/10** | 带权主观评估,用于维护排序,不是兼容性结论 |
|
|
||||||
|
|
||||||
综合分采用带权主观评估:文件树与职责 15%,核心算法命名和顺序 20%,磁盘 ABI
|
|
||||||
头文件可同步性 20%,FreeBSD API 与构建集成 20%,代码卫生与 style(9) 15%,社区
|
|
||||||
文档与基线可复现性 10%。计算为
|
|
||||||
`8.0*0.15 + 8.5*0.20 + 6.0*0.20 + 9.0*0.20 + 5.5*0.15 + 5.0*0.10 = 7.225`,
|
|
||||||
按一位小数四舍五入为 `7.2/10`。权重反映本任务更重视算法、ABI 和平台集成,仍不
|
|
||||||
应视为客观兼容性指标。
|
|
||||||
|
|
||||||
从第三方维护者视角,当前更准确的描述是:核心算法和主要 FreeBSD 适配已对齐,
|
|
||||||
但仍存在明确的 correctness 风险、结构漂移、代码卫生和可追溯性工作。
|
|
||||||
|
|
||||||
## 12. 后续执行路线
|
|
||||||
|
|
||||||
本报告只给出路线,不执行任何修改。
|
|
||||||
|
|
||||||
### 第一批:先处理两个 P1
|
|
||||||
|
|
||||||
1. 修复 `insmntque()` 失败后的 vnode UAF。
|
|
||||||
2. 对 chunk/physical read 建立严格分块上限,修复 `uiomove(int)` 宽度问题。
|
|
||||||
3. 为两个问题分别新增 Markdown 手工测试和独立 FreeBSD 动态报告。
|
|
||||||
|
|
||||||
该批次必须最小化变更面,不能混入文件重排或 style 清理。
|
|
||||||
|
|
||||||
### 第二批:P2 correctness 与边界测试
|
|
||||||
|
|
||||||
1. 目录全局严格排序验证与 namecache 负项检查。
|
|
||||||
2. root vnode `VDIR` 验证。
|
|
||||||
3. compact pblk 64-bit checked addition。
|
|
||||||
4. 量化 explicit extent 首次 O(N) 扫描,并决定预算/缓存策略。
|
|
||||||
|
|
||||||
每项一份或一组明确 Markdown 测试,复用既有 fixture helper,但不实现 CI。
|
|
||||||
|
|
||||||
### 第三批:P3 correctness、compatibility 与 semantic/style
|
|
||||||
|
|
||||||
1. correctness/API 契约:保留原 P3 严重度,分别修正 DEFLATE 分配失败 errno、
|
|
||||||
48-bit end-exclusive 最后合法完整块边界,以及 birthtime-only `VOP_SETATTR()`
|
|
||||||
的只读语义。
|
|
||||||
2. compatibility/格式语义:确认并实现 Linux 负时间戳兼容语义;明确 inline symlink
|
|
||||||
内嵌 NUL 的格式政策并补充拒绝或兼容测试。
|
|
||||||
3. semantic/style:删除或改写不可达的 FRAGMENTS 特例分支,使注释、supported mask
|
|
||||||
和真实支持边界一致。
|
|
||||||
|
|
||||||
六项均需各自的 Markdown 手工测试或同类成组测试,不得因进入后续批次而改变本报告
|
|
||||||
中的 P3 严重度。
|
|
||||||
|
|
||||||
### 第四批:低风险卫生、文档和 provenance
|
|
||||||
|
|
||||||
1. 删除或隔离 repo17/repo19 历史脚本和失配 C harness。
|
|
||||||
2. 清理 `xattr.h`、`internal.h`、`erofs_defs.h` 的死声明和死宏。
|
|
||||||
3. 修正 architecture 文档、零拷贝表述和 Linux 基线复现信息。
|
|
||||||
4. 增加 LICENSE/COPYING、许可证构成和来源 manifest。
|
|
||||||
5. 确认 UDF helper 和本地实现的作者归属。
|
|
||||||
6. 在规则明确后处理 style(9) 的确定性问题。
|
|
||||||
|
|
||||||
### 第五批:结构重排和压缩职责对齐
|
|
||||||
|
|
||||||
1. 恢复 `erofs_fs.h` 非平台相关定义顺序、注释和名称。
|
|
||||||
2. 评估把压缩配置 loader 移回各 backend。
|
|
||||||
3. 统一内部 `z_erofs_*` 命名和函数定义顺序。
|
|
||||||
4. 删除无行为包装,调整非必要函数位置差异。
|
|
||||||
|
|
||||||
该批次风险高于普通 style,必须用双配置构建、模块加载和全部相关 Markdown 测试
|
|
||||||
证明无行为变化。
|
|
||||||
|
|
||||||
### 第六批:性能原型
|
|
||||||
|
|
||||||
1. LZMA decoder state pool/cache。
|
|
||||||
2. explicit extent 验证缓存或分段策略。
|
|
||||||
3. `vfs_read_dirent()` 输出适配器。
|
|
||||||
|
|
||||||
原型必须提供基线、压力方法、内存峰值、卸载清理和退化行为;没有数据不合并。
|
|
||||||
|
|
||||||
## 13. 原任务三个目标的覆盖矩阵
|
|
||||||
|
|
||||||
| 原任务目标 | 已确认正向证据 | 本轮发现 | 尚未验证/后续 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 1. 最佳实践与 BSD 原生能力复用 | GEOM/bread、vfs_hash、pager、ACL/extattr、CRC/endian、DEFLATE/ZSTD 复用正确;LZ4/MicroLZMA 本地实现有技术理由 | `insmntque()` 契约违反;chunk 大分配;dir helper 需保留但可原型化输出层;LZMA per-call allocation | 动态复现 P1;XZ KPI、dir adapter、LZMA pool 原型 |
|
|
||||||
| 2. 正确处理 BSD/Linux 行为差异 | 正 errno、VOP/VFS、GEOM、namecache、cookie、ACL namespace、FID/generation 等必要差异清晰 | root 类型、setattr、errno、负时间;compact/48-bit/排序属于 Linux 共同问题,未误记为 BSD 差异 | negative time、symlink NUL、fragment pstart_hi 格式语义确认 |
|
|
||||||
| 3. 第三方维护者相似性 | 15 个共同文件;namei/zmap 和 Makefile 顺序质量高;未伪造 Linux-only 空文件 | erofs_fs 顺序/注释、压缩职责/命名、死代码、旧脚本、陈旧文档、style、provenance、许可证清单 | 逐批结构重排、来源确认、外部可复现基线、回归验证 |
|
|
||||||
|
|
||||||
因此,三个目标都已有实质正向成果,但目标 3 明显未达到“没有任何非必要差异”
|
|
||||||
的完成标准;目标 1 和目标 2 也因两个 P1 和若干 P2/P3 finding 需要继续工作。
|
|
||||||
|
|
||||||
## 14. 与 report-3 的关系
|
|
||||||
|
|
||||||
`current/report-3` 是任务 1 收尾时的历史快照。它关于 161 项 feature 手工验证、
|
|
||||||
构建、清理和当时已知 issue 的证据继续有效,本报告不修改也不重写这些结论。
|
|
||||||
|
|
||||||
但 report-3 中“未发现仍需消除的非必要 Linux/FreeBSD 结构、命名或职责差异”是
|
|
||||||
一个超出当时证据范围的绝对表述。当时没有保存:
|
|
||||||
|
|
||||||
- 全部文件的函数、变量和定义顺序对照;
|
|
||||||
- FreeBSD 原生 API 复用清单;
|
|
||||||
- Linux-only/BSD-only 文件逐项必要性论证;
|
|
||||||
- 死代码、失效入口、style(9)、来源和许可证审计;
|
|
||||||
- 独立仓库可重建的 Linux 基线 provenance。
|
|
||||||
|
|
||||||
因此,对任务 2 应以本报告作更精确限定:
|
|
||||||
|
|
||||||
> repo22 的核心算法和主要 FreeBSD 适配已取得良好对齐,但尚不能认定全面完成
|
|
||||||
> code review 和 style 优化;仍存在两个 P1、四个 P2、六个 P3,以及明确的结构、
|
|
||||||
> 代码卫生、style 和可追溯性工作。
|
|
||||||
|
|
||||||
该限定不回写 report-3,以保持历史报告不可变和审计链清晰。
|
|
||||||
|
|
||||||
## 15. 最终状态
|
|
||||||
|
|
||||||
- 本轮只创建 `current/report-4/`。
|
|
||||||
- 未修改 `src/`、`tests/`、`docs/`、`issues/`、既有 report 或 CI。
|
|
||||||
- 未声称任何 finding 已修复。
|
|
||||||
- 未把静态候选误写成动态复现结果。
|
|
||||||
- 新问题进入后续计划前,应先创建对应 Markdown 手工测试规格,再由独立执行者在
|
|
||||||
FreeBSD 15 环境中复现、修复和回归。
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# report-4:任务 2 代码审查与风格评估
|
|
||||||
|
|
||||||
本目录记录 2026-08-10 对 repo22 原任务中“任务 2:进行全面的 code review
|
|
||||||
和 style 优化”的只读调查结果。
|
|
||||||
|
|
||||||
本次工作只做静态评估、源码契约核对、Linux/FreeBSD 严格比对、历史检查和
|
|
||||||
机械 style 检查,不修改生产源码、测试、既有文档、issues 或 CI。报告中的新
|
|
||||||
finding 尚未在 FreeBSD 虚拟机中动态复现,也尚未修复。
|
|
||||||
|
|
||||||
## 审计基线
|
|
||||||
|
|
||||||
- BSD 目标:`repo-community/repo22`,提交
|
|
||||||
`76cfb553e0951b428f9d426933a10d1fe18d2a0e`
|
|
||||||
- 最终源码变更提交:`67d3c057fbcad5adc765ab9927da511e3221ac8f`
|
|
||||||
- repo22 `src/` tree:`a605af0f01f83d67c199005e775e1a47a1610036`
|
|
||||||
- Linux 独立参考:`/work/dev-src-linux/fs/erofs`,Linux 7.1.0-rc1
|
|
||||||
- Linux 本地导入提交:`8be2be573d2b191c83d760b65c554f78eb95893c`
|
|
||||||
- Linux EROFS tree:`b79b9a8b62f633e887a8b99075ff9412fabd7f83`
|
|
||||||
- FreeBSD API 参考:`/work/dev-freebsd-releng`,15.0-RELEASE-p9
|
|
||||||
|
|
||||||
## 结论摘要
|
|
||||||
|
|
||||||
- 任务 1 的 161 项 feature 验证结论不在本报告中重写,也不因本报告自动失效。
|
|
||||||
- 任务 2 尚不能认定已经全面完成。本轮确认 `P0=0`、`P1=2`、`P2=4`、
|
|
||||||
`P3=6`,另有若干非 correctness 的结构、style、来源与性能原型工作。
|
|
||||||
- FreeBSD 原生 API 和构建集成总体合理,强行复用并不适用于 LZ4、MicroLZMA
|
|
||||||
和目录 cookie helper。
|
|
||||||
- 核心算法映射质量较高,但磁盘 ABI 头文件顺序、压缩职责、死代码、历史测试
|
|
||||||
入口、文档、style(9) 和外部可复现性仍有明确维护债务。
|
|
||||||
- 综合维护者相似度暂评为 `7.2/10`。该分数仅用于排序维护工作,不是客观质量
|
|
||||||
或兼容性指标。
|
|
||||||
|
|
||||||
## 文档索引
|
|
||||||
|
|
||||||
- [任务 2 详细代码审查与风格评估](2026-08-10-task2-code-review-style-assessment.md)
|
|
||||||
|
|
||||||
## 与既有报告的关系
|
|
||||||
|
|
||||||
`current/report-1` 至 `current/report-3` 保持历史快照。本目录不修改它们。
|
|
||||||
report-3 的 feature 验证结果继续作为任务 1 证据;其中“没有非必要差异”的绝对
|
|
||||||
表述,由本次更完整的结构、style、来源和许可证审计作更精确的限定。
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# Manual Test Evidence
|
|
||||||
|
|
||||||
## Final Status
|
|
||||||
|
|
||||||
repo22 has 161 executable manual test cases, TC001-TC161, plus the non-executable
|
|
||||||
TC000 template. The canonical dated reports produce:
|
|
||||||
|
|
||||||
| Status | Count |
|
|
||||||
| --- | ---: |
|
|
||||||
| PASS | 160 |
|
|
||||||
| PARTIAL | 1 |
|
|
||||||
| FAIL / KERNEL-FAIL | 0 |
|
|
||||||
| ENVIRONMENT-UNAVAILABLE | 0 |
|
|
||||||
| SHELVED test case | 0 |
|
|
||||||
|
|
||||||
TC146 is the single PARTIAL case. Its HEAD2 and interlaced paths pass, while
|
|
||||||
the explicit mapped-payload positive fixture remains unavailable. That
|
|
||||||
shelved subitem is not counted as a second test case.
|
|
||||||
|
|
||||||
## Evidence Policy
|
|
||||||
|
|
||||||
Authoritative evidence consists of the numbered Markdown procedures,
|
|
||||||
deterministic field-asserting fixture helpers, native syscall/kernel probes,
|
|
||||||
and dated `tests/results/manual/*/manual-test-report.md` reports. Reports record
|
|
||||||
the exact source, module or fixture hashes, FreeBSD kernel behavior, errno, and
|
|
||||||
cleanup state.
|
|
||||||
|
|
||||||
Host-only fixture generation, static ABI review, and userspace erofs-utils
|
|
||||||
output are supporting evidence. They do not replace a required FreeBSD kernel
|
|
||||||
result. The suite is manual-only; no CI pipeline or automated kernel-test
|
|
||||||
harness is implemented or claimed.
|
|
||||||
|
|
||||||
## Canonical Runs
|
|
||||||
|
|
||||||
The final status uses these non-overlapping report groups for TC001-TC156:
|
|
||||||
|
|
||||||
| Group | Exact scope | Result |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| G1 | 32 IDs | 32 PASS |
|
|
||||||
| G2 | 13 IDs | 13 PASS |
|
|
||||||
| G3 | 31 IDs | 31 PASS after the dated TC060 fixed-source rerun |
|
|
||||||
| G4 | 27 IDs | 27 PASS |
|
|
||||||
| G5 | 24 IDs | 23 PASS, TC146 PARTIAL |
|
|
||||||
| G6 | 11 IDs | 11 PASS |
|
|
||||||
| G7 | 11 IDs | 11 PASS |
|
|
||||||
| G8 | 7 IDs | 7 PASS |
|
|
||||||
|
|
||||||
The G1-G8 tables contain exactly 156 rows and 156 unique IDs, with no missing
|
|
||||||
or duplicate TC from TC001-TC156. TC060's original G3 KERNEL-FAIL is historical
|
|
||||||
and is superseded by
|
|
||||||
`tests/results/manual/2026-08-09T1120Z-tc060-fix/manual-test-report.md`.
|
|
||||||
TC153 passed in the final G3 run and its issue is resolved.
|
|
||||||
|
|
||||||
TC157-TC161 are recorded in
|
|
||||||
`tests/results/manual/2026-08-09T1804Z-final-review-independent/manual-test-report.md`.
|
|
||||||
All five pass on exact source baseline
|
|
||||||
`fcc85b93d5f8fd9671686bd68bf3b086c8bd25cf`.
|
|
||||||
|
|
||||||
## TC111 Coverage Audit
|
|
||||||
|
|
||||||
A bounded audit of `tests/TC[0-9][0-9][0-9]-*.md` found 162 rows and 162 unique
|
|
||||||
IDs, TC000-TC161, with no missing or duplicate ID. Excluding TC000 leaves 161
|
|
||||||
executable specifications.
|
|
||||||
|
|
||||||
The audit also cross-checked the eight canonical group tables and the five
|
|
||||||
final-review rows. Final arithmetic is `155 PASS + 1 PARTIAL + 5 PASS`, or
|
|
||||||
160 PASS and one PARTIAL.
|
|
||||||
|
|
||||||
## Final Build Qualification
|
|
||||||
|
|
||||||
The final independent run rebuilt both configurations after the TC161 failing
|
|
||||||
`nm` shim and used `/usr/bin/nm` for the post-shim build:
|
|
||||||
|
|
||||||
| Configuration | KLD SHA256 |
|
|
||||||
| --- | --- |
|
|
||||||
| `WITH_ZSTDIO=0` | `15fda9d334132cd81769ce4dff4f8411a6e2b4cf7531c352530d0de85f42a2d2` |
|
|
||||||
| `WITH_ZSTDIO=1` | `23782dc0ce7da188807d35020bf2d8c6044b796c5c9a8746b398ba784cd6ad4e` |
|
|
||||||
|
|
||||||
Both KLDs loaded, mounted a qualified image read-only, unmounted, detached the
|
|
||||||
md provider, and unloaded. Final guest mount, md, EROFS KLD, and DTrace KLD
|
|
||||||
counts were zero.
|
|
||||||
|
|
||||||
G1-G8 evidence was collected across multiple source commits. It is not claimed
|
|
||||||
that all historical tests ran on the final KLD. The final code baseline was
|
|
||||||
independently exercised by TC157-TC161 and the affected dual-build,
|
|
||||||
module-load, and mount smoke.
|
|
||||||
|
|
||||||
## Issue Status
|
|
||||||
|
|
||||||
- TC010: RESOLVED by a real 16 TiB-plus sparse-provider statfs run.
|
|
||||||
- TC060: RESOLVED by the FreeBSD pathconf fix and exact-source rerun.
|
|
||||||
- TC153: RESOLVED by the multi-TiB Layout 0 directory lookup run.
|
|
||||||
- Explicit mapped payload: SHELVED as a detailed fixture/tooling limitation;
|
|
||||||
TC146 remains PARTIAL.
|
|
||||||
|
|
||||||
See `issues/README.md` for the current index and the individual files for
|
|
||||||
triggers, analysis, attempts, results, feature impact, and acceptance criteria.
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
# repo22 架构设计
|
|
||||||
|
|
||||||
## 设计目标
|
|
||||||
|
|
||||||
repo22 提供尽量贴近 Linux `fs/erofs` 职责划分的 FreeBSD 15
|
|
||||||
只读实现,同时对 FreeBSD vnode、GEOM、pager、`dev_t` 和 NFS FID 语义做
|
|
||||||
必要适配。
|
|
||||||
|
|
||||||
## 核心原则
|
|
||||||
|
|
||||||
1. **Linux 对齐**:函数命名、文件组织、代码排序尽可能匹配 Linux 版本
|
|
||||||
2. **最小抽象**:避免不必要的封装层
|
|
||||||
3. **安全优先**:保留 repo19 的所有安全修复
|
|
||||||
4. **可维护性**:便于社区维护和与上游同步
|
|
||||||
|
|
||||||
## 文件组织
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── super.c - 超级块、挂载、VFS 集成
|
|
||||||
├── inode.c - inode 读取和 vnode 管理
|
|
||||||
├── data.c - 数据块映射和解压缩
|
|
||||||
├── namei.c - 路径查找(二分搜索)
|
|
||||||
├── dir.c - 目录遍历和输出
|
|
||||||
├── xattr.c - 扩展属性和 ACL
|
|
||||||
├── erofs_vnops.c - VFS vnode 操作实现
|
|
||||||
├── decompressor.c - 压缩配置解析和统一调度
|
|
||||||
├── lz4.c - FreeBSD 有界 LZ4 后端
|
|
||||||
├── decompressor_lzma.c - MicroLZMA 后端
|
|
||||||
├── decompressor_deflate.c - DEFLATE 后端
|
|
||||||
├── decompressor_zstd.c - 可选 ZSTDIO 后端
|
|
||||||
├── zmap.c - 压缩逻辑块映射
|
|
||||||
├── zdata.c - 压缩数据读取
|
|
||||||
├── internal.h - 内存结构和内部 API
|
|
||||||
├── erofs_fs.h - 磁盘格式定义
|
|
||||||
├── xattr.h - 扩展属性接口
|
|
||||||
└── erofs_defs.h - 常量定义
|
|
||||||
```
|
|
||||||
|
|
||||||
## 分层架构
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ VFS 层 (FreeBSD kernel) │
|
|
||||||
└─────────────┬───────────────────────┘
|
|
||||||
│
|
|
||||||
┌─────────────▼───────────────────────┐
|
|
||||||
│ VFS 接口层 │
|
|
||||||
│ - erofs_vnops.c │
|
|
||||||
│ - super.c (mount/unmount/root) │
|
|
||||||
└─────────────┬───────────────────────┘
|
|
||||||
│
|
|
||||||
┌─────────────▼───────────────────────┐
|
|
||||||
│ 文件系统逻辑层 │
|
|
||||||
│ - inode.c (erofs_read_inode) │
|
|
||||||
│ - namei.c (erofs_namei) │
|
|
||||||
│ - dir.c (erofs_readdir_block) │
|
|
||||||
│ - xattr.c (erofs_getxattr) │
|
|
||||||
└─────────────┬───────────────────────┘
|
|
||||||
│
|
|
||||||
┌─────────────▼───────────────────────┐
|
|
||||||
│ 数据访问层 │
|
|
||||||
│ - data.c (erofs_map_blocks) │
|
|
||||||
│ - data.c (erofs_read_data) │
|
|
||||||
│ - zmap.c / zdata.c │
|
|
||||||
│ - decompressor.c (z_erofs_decompress) │
|
|
||||||
└─────────────┬───────────────────────┘
|
|
||||||
│
|
|
||||||
┌─────────────▼───────────────────────┐
|
|
||||||
│ 块 I/O 层 │
|
|
||||||
│ - erofs_bread/erofs_brelse │
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心数据结构
|
|
||||||
|
|
||||||
### erofs_mount (内存中的文件系统状态)
|
|
||||||
```c
|
|
||||||
struct erofs_mount {
|
|
||||||
struct mount *mnt; // FreeBSD mount 结构
|
|
||||||
struct vnode *devvp; // 块设备 vnode
|
|
||||||
struct g_consumer *cp; // GEOM consumer
|
|
||||||
|
|
||||||
uint32_t block_size; // 块大小
|
|
||||||
uint64_t root_nid; // 根目录 NID
|
|
||||||
uint32_t feature_compat; // 特性标志
|
|
||||||
uint32_t feature_incompat;
|
|
||||||
|
|
||||||
struct erofs_sb_lz4_info lz4; // LZ4 参数
|
|
||||||
struct erofs_deviceslot *devs; // 设备表
|
|
||||||
struct erofs_xattr_prefix_item *xattr_prefixes; // xattr 前缀表
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### erofs_node (内存中的 inode)
|
|
||||||
```c
|
|
||||||
struct erofs_node {
|
|
||||||
struct vnode *vnode; // 关联的 vnode
|
|
||||||
uint64_t nid; // 节点 ID
|
|
||||||
uint64_t size; // 文件大小
|
|
||||||
uint8_t datalayout; // 数据布局类型
|
|
||||||
|
|
||||||
// 压缩相关
|
|
||||||
uint8_t z_algorithmformat;
|
|
||||||
uint8_t z_lclusterbits;
|
|
||||||
|
|
||||||
// Chunk-based 相关
|
|
||||||
uint16_t chunkformat;
|
|
||||||
uint8_t chunkbits;
|
|
||||||
|
|
||||||
// Fragment 相关
|
|
||||||
uint32_t fragmentoff;
|
|
||||||
bool fragment;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## 关键实现细节
|
|
||||||
|
|
||||||
### 1. 数据布局支持
|
|
||||||
|
|
||||||
支持 4 种数据布局:
|
|
||||||
- **FLAT_PLAIN**: 连续块
|
|
||||||
- **FLAT_INLINE**: 最后一个逻辑块位于 inode metadata block 内,且受声明
|
|
||||||
image/metabox bounds 约束
|
|
||||||
- **CHUNK_BASED**: 固定大小 chunk,支持稀疏文件
|
|
||||||
- **COMPRESSED**: 可变大小压缩 cluster
|
|
||||||
|
|
||||||
### 2. 压缩算法
|
|
||||||
|
|
||||||
支持 4 种压缩算法及未压缩 transform:
|
|
||||||
- LZ4 (LZ4HC)
|
|
||||||
- LZMA
|
|
||||||
- DEFLATE
|
|
||||||
- ZSTD
|
|
||||||
- 未压缩
|
|
||||||
|
|
||||||
### 3. 高级特性
|
|
||||||
|
|
||||||
- ✅ **ztailpacking**: 压缩文件尾部内联
|
|
||||||
- ✅ **fragments**: 已验证的 fragment-backed 压缩文件与 metabox carrier
|
|
||||||
- ⚠️ **dedupe**: 仅声明已验证的 fragment/partial-reference 形式,不宣称
|
|
||||||
覆盖所有未来编码
|
|
||||||
- ✅ **xattr_prefixes**: 共享 xattr 前缀表
|
|
||||||
- ✅ **device_table**: 多设备支持
|
|
||||||
- ✅ **metabox**: 每 inode 元数据盒
|
|
||||||
|
|
||||||
### 4. 安全机制
|
|
||||||
|
|
||||||
repo22 的边界策略:
|
|
||||||
- 所有指针操作前检查边界
|
|
||||||
- 所有算术运算检查溢出
|
|
||||||
- 所有分配检查大小合理性
|
|
||||||
- 递归深度限制
|
|
||||||
- 设备 ID 和块地址验证
|
|
||||||
|
|
||||||
## 与 Linux 版本的差异
|
|
||||||
|
|
||||||
### 对照基线
|
|
||||||
|
|
||||||
本轮维护逐文件对照工作区中的 `/work/dev-src-linux/fs/erofs`。该目录是导入的
|
|
||||||
Linux 7.1-rc1 EROFS 参考快照;对照不依赖 repo22 与 Linux 树具有共同 Git
|
|
||||||
历史。`/work/linux-src/fs/erofs` 中对应文件与该精简快照字节一致,但不是本轮
|
|
||||||
文件映射的依据。
|
|
||||||
|
|
||||||
### 必要差异(FreeBSD 适配)
|
|
||||||
|
|
||||||
1. **内存分配**:使用 `malloc(..., M_EROFS, ...)` 而非 `kmalloc()`
|
|
||||||
2. **块 I/O**:通过 GEOM consumer 和 FreeBSD vnode/buffer 接口读取 provider
|
|
||||||
3. **VFS 接口**:`erofs_vnops.c` 实现 FreeBSD `vop_vector`,不照搬 Linux
|
|
||||||
`inode_operations`、folio 或 iomap 接口
|
|
||||||
4. **错误约定**:内核入口返回正的 FreeBSD errno;Linux 负 errno 或
|
|
||||||
`ERR_PTR` 仅作为算法对照,不能机械移植
|
|
||||||
5. **压缩后端**:BSD 调度器跨编译单元调用 `internal.h` 中的简单后端 API;
|
|
||||||
Linux 使用 `struct z_erofs_decompressor` 和不同的内存/页面生命周期
|
|
||||||
6. **LZ4 文件职责**:BSD 保留独立 `lz4.c` 有界解码器;Linux LZ4 路径位于
|
|
||||||
`decompressor.c` 并依赖 Linux 内核 LZ4/page API
|
|
||||||
7. **平台特性**:Linux `sysfs.c`、`fileio.c`、`fscache.c`、`ishare.c` 和
|
|
||||||
`zutil.c` 没有无条件对应物,不为文件外观引入空包装
|
|
||||||
8. **构建架构**:当前只验证 FreeBSD 15 amd64,Makefile 明确拒绝其他
|
|
||||||
`MACHINE_ARCH`
|
|
||||||
|
|
||||||
### 保持一致的部分
|
|
||||||
|
|
||||||
- 静态目录 helper 使用 Linux 名称 `find_target_dirent`
|
|
||||||
- LZMA、DEFLATE、ZSTD 后端使用 Linux 文件名 `decompressor_*.c`
|
|
||||||
- Makefile 先列 metadata/VFS 文件,再列压缩调度、映射和后端文件
|
|
||||||
- 跨文件后端声明集中在 `internal.h`,不在调用方手写 `extern`
|
|
||||||
- `erofs_fs.h` 的磁盘格式定义和核心目录/映射算法按 Linux 语义核对
|
|
||||||
|
|
||||||
## 代码规范
|
|
||||||
|
|
||||||
### 命名约定
|
|
||||||
- 公共函数:`erofs_<module>_<action>`
|
|
||||||
- 静态函数:描述性名称,无固定前缀
|
|
||||||
- 宏:`EROFS_*` 全大写
|
|
||||||
- 结构体:`struct erofs_*`
|
|
||||||
|
|
||||||
### 函数排序(每个文件)
|
|
||||||
1. 辅助函数(static)
|
|
||||||
2. 核心逻辑函数
|
|
||||||
3. VFS 接口函数
|
|
||||||
4. 模块注册/清理(仅 super.c)
|
|
||||||
|
|
||||||
### 错误处理
|
|
||||||
```c
|
|
||||||
int erofs_function(...)
|
|
||||||
{
|
|
||||||
int error = 0;
|
|
||||||
void *buf = NULL;
|
|
||||||
|
|
||||||
// 操作...
|
|
||||||
if (条件) {
|
|
||||||
error = EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
if (buf)
|
|
||||||
erofs_brelse(buf);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 测试策略
|
|
||||||
|
|
||||||
### 单元测试
|
|
||||||
|
|
||||||
不存在受支持的用户态单元测试入口。旧的 `src/Makefile.test` 从错误目录引用
|
|
||||||
`test_decompress.c`,并尝试把内核解压源码按不匹配的用户态 ABI 链接;该入口已
|
|
||||||
删除,不能作为可运行测试或 feature 验证证据。
|
|
||||||
|
|
||||||
旧的 `test_super.c` 和 `test_inode.c` 只重复了测试文件中的公式,并未调用
|
|
||||||
内核生产解析路径,其中 inode harness 还引用过已删除的磁盘字段。它们已退役,
|
|
||||||
不得作为 feature 验证证据。superblock、inode、pager 和错误路径必须使用
|
|
||||||
`TC*.md` 中的确定性镜像,经 FreeBSD 内核模块实际挂载或访问验证。
|
|
||||||
|
|
||||||
### 集成测试
|
|
||||||
|
|
||||||
仓库根目录遗留的 `test_all_decompress.sh` 和 `test_chunk_based.sh` 包含其他
|
|
||||||
repo 的硬编码路径,不能作为 repo22 的测试入口或验收证据。受支持的验证方式是
|
|
||||||
直接执行 `tests/TC*.md` 中记录的 FreeBSD 15 内核步骤,并将命令、errno、哈希和
|
|
||||||
清理状态写入 `tests/results/manual/` 下的日期报告。
|
|
||||||
|
|
||||||
### VM 测试
|
|
||||||
- 挂载真实镜像
|
|
||||||
- 文件读取验证
|
|
||||||
- 性能基准测试
|
|
||||||
|
|
||||||
## 维护指南
|
|
||||||
|
|
||||||
### 同步上游 Linux 变更
|
|
||||||
|
|
||||||
1. 选定明确的 Linux `fs/erofs` 快照;当前工作区基线为
|
|
||||||
`/work/dev-src-linux/fs/erofs`
|
|
||||||
2. 逐文件识别修改,不假设两个实现共享提交历史
|
|
||||||
3. 检查是否为磁盘格式变更(`erofs_fs.h`)或 Linux 专属 VFS/page API
|
|
||||||
4. 只移植语义上适用的算法,并保留 FreeBSD errno、锁、GEOM 和 vnode 约定
|
|
||||||
5. 运行双配置构建、模块加载和真实镜像挂载测试
|
|
||||||
|
|
||||||
### 添加新特性
|
|
||||||
|
|
||||||
1. 在 `erofs_fs.h` 添加磁盘格式定义
|
|
||||||
2. 在 `internal.h` 添加内存结构
|
|
||||||
3. 实现解析逻辑(data.c/inode.c)
|
|
||||||
4. 添加确定性 fixture 和对应的 `TC*.md` 内核测试
|
|
||||||
5. 更新文档
|
|
||||||
|
|
||||||
## 性能考虑
|
|
||||||
|
|
||||||
- **零拷贝**:直接从缓冲区缓存读取
|
|
||||||
- **延迟加载**:仅在需要时读取 inode 元数据
|
|
||||||
- **缓存友好**:利用 FreeBSD 的 vnode 缓存
|
|
||||||
- **批量操作**:目录读取一次性处理多个条目
|
|
||||||
|
|
||||||
## 已知限制
|
|
||||||
|
|
||||||
- 不支持写操作(只读文件系统)
|
|
||||||
- 不支持 FUSE 模式
|
|
||||||
- 构建和运行时验证目前仅覆盖 FreeBSD 15 amd64
|
|
||||||
- 不实现 Linux file-backed、fscache、page-cache sharing 或 sysfs 控制面
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# repo-pre-2 Capability Record
|
|
||||||
|
|
||||||
## Status Vocabulary
|
|
||||||
|
|
||||||
This document separates inherited pre1 claims from fresh pre2 validation:
|
|
||||||
|
|
||||||
- `INHERITED CLAIM`: documented by the unchanged pre1 snapshot; not re-tested
|
|
||||||
for pre2.
|
|
||||||
- `STATIC GATE`: visible in tracked source or build declarations; runtime
|
|
||||||
behavior was not exercised.
|
|
||||||
- `NOT IMPLEMENTED`: explicitly excluded by inherited project documentation.
|
|
||||||
- `NOT CLAIMED`: inherited documentation deliberately limits the support
|
|
||||||
claim.
|
|
||||||
- `NOT RUN`: no build or runtime validation was performed for repo-pre-2.
|
|
||||||
|
|
||||||
`INHERITED CLAIM` is provenance, not a new PASS result. Existing reports under
|
|
||||||
`tests/results/manual/` describe earlier pre1 work and must not be cited as a
|
|
||||||
fresh repo-pre-2 execution.
|
|
||||||
|
|
||||||
## Snapshot Evidence
|
|
||||||
|
|
||||||
```text
|
|
||||||
repo-pre-1 source tree: 6a5a1a49d4a4e08f6ef1155de240500e63a15365
|
|
||||||
repo-pre-2 initial tree: 6a5a1a49d4a4e08f6ef1155de240500e63a15365
|
|
||||||
src-linux reference tree: b79b9a8b62f633e887a8b99075ff9412fabd7f83
|
|
||||||
runtime validation: NOT RUN
|
|
||||||
```
|
|
||||||
|
|
||||||
The inherited claims below are transcribed at category level from `README.md`
|
|
||||||
and `docs/features.md`. They are not an independent feature review.
|
|
||||||
|
|
||||||
## Capability Matrix
|
|
||||||
|
|
||||||
| Area | Inherited pre1 claim or static declaration | Pre2 status |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Mount and metadata | Read-only mount/unmount, `statfs`, superblock checksum and bounds, compact/extended inodes, 48-bit fields | INHERITED CLAIM; NOT RUN |
|
|
||||||
| Plain data | Flat plain, flat inline, tail bounds, and logical block accounting | INHERITED CLAIM; NOT RUN |
|
|
||||||
| Chunk and devices | Chunk indexes, holes, device tables, explicit devices, and flatdev mapping | INHERITED CLAIM; NOT RUN |
|
|
||||||
| Compressed data | LZ4, MicroLZMA, DEFLATE, full/compact indexes, partial references, HEAD2, ztailpacking, and qualified fragment forms | INHERITED CLAIM; NOT RUN |
|
|
||||||
| ZSTD | Source is always listed; `WITH_ZSTDIO=1` adds `ZSTDIO`, while the default is `0` | STATIC GATE; runtime NOT RUN |
|
|
||||||
| Directories and vnode operations | Lookup, readdir, cookies, namecache, access, readlink, pathconf, pager integration, and read-only mutation rejection | INHERITED CLAIM; NOT RUN |
|
|
||||||
| Xattrs and ACLs | Inline/shared namespaces, metabox storage, long/packed prefixes, and POSIX ACL reads | INHERITED CLAIM; NOT RUN |
|
|
||||||
| NFS export | 64-bit NIDs, generation handling, and malformed/stale handle validation | INHERITED CLAIM; NOT RUN |
|
|
||||||
| Build target | `src/Makefile` rejects architectures other than `amd64` | STATIC GATE; build NOT RUN |
|
|
||||||
| Write support | Writable filesystem operations | NOT IMPLEMENTED |
|
|
||||||
| `VOP_BMAP` | Explicitly unsupported in inherited documentation | NOT IMPLEMENTED |
|
|
||||||
| Complete future-format parity | All future incompat features and every dedupe encoding | NOT CLAIMED |
|
|
||||||
| Explicit compressed-extent positive payload | Inherited documentation records only partial coverage | NOT CLAIMED; NOT RUN |
|
|
||||||
| Performance guarantees | Manual observations are not a performance contract | NOT CLAIMED |
|
|
||||||
|
|
||||||
## Interpretation Rules
|
|
||||||
|
|
||||||
1. Source presence, feature-bit definitions, or build selection do not prove a
|
|
||||||
runtime capability.
|
|
||||||
2. A pre1 manual report does not become a pre2 PASS merely because the initial
|
|
||||||
trees match.
|
|
||||||
3. Phase 1 mechanical edits must not expand or reduce this capability matrix.
|
|
||||||
4. A future status change requires recorded evidence from an actually executed
|
|
||||||
validation step.
|
|
||||||
|
|
||||||
## Current Validation Declaration
|
|
||||||
|
|
||||||
No build, QEMU execution, test script, smoke test, mount, malformed-image
|
|
||||||
probe, or performance measurement was run for this initialization. The current
|
|
||||||
repo-pre-2 runtime validation result is therefore `NOT RUN` in every category.
|
|
||||||
-271
@@ -1,271 +0,0 @@
|
|||||||
.\" Copyright (c) 2026
|
|
||||||
.\" All rights reserved.
|
|
||||||
.\"
|
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
|
||||||
.\" modification, are permitted provided that the following conditions
|
|
||||||
.\" are met:
|
|
||||||
.\" 1. Redistributions of source code must retain the above copyright
|
|
||||||
.\" notice, this list of conditions and the following disclaimer.
|
|
||||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
.\" notice, this list of conditions and the following disclaimer in the
|
|
||||||
.\" documentation and/or other materials provided with the distribution.
|
|
||||||
.\"
|
|
||||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
.\" SUCH DAMAGE.
|
|
||||||
.\"
|
|
||||||
.Dd August 9, 2026
|
|
||||||
.Dt EROFS 5
|
|
||||||
.Os
|
|
||||||
.Sh NAME
|
|
||||||
.Nm erofs
|
|
||||||
.Nd Enhanced Read-Only File System
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
To mount an
|
|
||||||
.Nm
|
|
||||||
volume:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
mount -t erofs /dev/da0 /mnt
|
|
||||||
.Ed
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
driver provides read-only support for the Enhanced Read-Only File System
|
|
||||||
(EROFS), a modern compressed read-only filesystem designed for space
|
|
||||||
efficiency and performance.
|
|
||||||
EROFS is widely used in Linux distributions and mobile systems for root
|
|
||||||
filesystems, firmware images, and container layers.
|
|
||||||
.Pp
|
|
||||||
The
|
|
||||||
.Fx
|
|
||||||
implementation supports multiple compression algorithms, various data layouts,
|
|
||||||
extended attributes, and multi-device configurations.
|
|
||||||
.Pp
|
|
||||||
The currently qualified build target is
|
|
||||||
.Fx 15
|
|
||||||
on
|
|
||||||
.Sy amd64 .
|
|
||||||
The module Makefile rejects other architectures because they have not been
|
|
||||||
validated against this implementation's kernel ABI.
|
|
||||||
.Sh FEATURES
|
|
||||||
.Ss Inode Types
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
driver supports both compact and extended inode formats:
|
|
||||||
.Bl -bullet -compact
|
|
||||||
.It
|
|
||||||
Compact inodes (32 bytes) for typical files
|
|
||||||
.It
|
|
||||||
Extended inodes (64 bytes) with extended metadata
|
|
||||||
.It
|
|
||||||
Special handling for single-link files
|
|
||||||
.It
|
|
||||||
Inline data (tailpacking) for small files
|
|
||||||
.El
|
|
||||||
.Ss Data Layouts
|
|
||||||
.Bl -bullet -compact
|
|
||||||
.It
|
|
||||||
.Sy FLAT_PLAIN :
|
|
||||||
Uncompressed contiguous data
|
|
||||||
.It
|
|
||||||
.Sy FLAT_INLINE :
|
|
||||||
Uncompressed data with inline tail
|
|
||||||
.It
|
|
||||||
.Sy Chunk-based :
|
|
||||||
Fixed-size chunks for multi-device support
|
|
||||||
.It
|
|
||||||
.Sy Compressed :
|
|
||||||
LZ4, DEFLATE, zstd, or LZMA compressed data with pcluster mapping
|
|
||||||
.El
|
|
||||||
.Ss Compression Algorithms
|
|
||||||
.Bl -tag -width "MicroLZMA"
|
|
||||||
.It Sy LZ4
|
|
||||||
Fast decompression for general-purpose use, including ztailpacking
|
|
||||||
(compressed tail in inode metadata)
|
|
||||||
.It Sy DEFLATE
|
|
||||||
Standard compression with good compression ratio
|
|
||||||
.It Sy zstd
|
|
||||||
High compression ratio when the module is built with
|
|
||||||
.Va WITH_ZSTDIO=1 .
|
|
||||||
ZSTD support is disabled by default
|
|
||||||
.Pq Va WITH_ZSTDIO=0 ,
|
|
||||||
and an enabled module requires a kernel built with
|
|
||||||
.Cd "options ZSTDIO" .
|
|
||||||
.It Sy LZMA/MicroLZMA
|
|
||||||
Maximum compression ratio for space-constrained environments
|
|
||||||
.El
|
|
||||||
.Ss Extended Attributes
|
|
||||||
.Bl -bullet -compact
|
|
||||||
.It
|
|
||||||
Shared extended attributes with metabox container support
|
|
||||||
.It
|
|
||||||
Inline extended attributes
|
|
||||||
.It
|
|
||||||
Long-prefix extended attribute support
|
|
||||||
.It
|
|
||||||
Packed prefix table support
|
|
||||||
.It
|
|
||||||
POSIX ACL support (access and default ACLs)
|
|
||||||
.El
|
|
||||||
.Pp
|
|
||||||
User namespace attributes are exposed without prefix; system namespace
|
|
||||||
attributes retain their full qualified names (trusted.*, security.*).
|
|
||||||
.Pp
|
|
||||||
Linux POSIX access/default ACL xattrs are decoded into
|
|
||||||
.Fx
|
|
||||||
POSIX.1e ACLs when present.
|
|
||||||
ACL and xattr mutation remains read-only.
|
|
||||||
.Ss Advanced Features
|
|
||||||
.Bl -bullet -compact
|
|
||||||
.It
|
|
||||||
Superblock CRC32C verification
|
|
||||||
.It
|
|
||||||
48-bit block count and root nid support
|
|
||||||
.It
|
|
||||||
Device table for multi-device volumes
|
|
||||||
.It
|
|
||||||
Qualified fragment-backed compressed files and metabox carriers
|
|
||||||
.It
|
|
||||||
VFS hash integration and namecache support
|
|
||||||
.It
|
|
||||||
Directory entry optimization (dot_omitted handling)
|
|
||||||
.It
|
|
||||||
NFS export with stable superblock-seeded per-inode file-handle generations
|
|
||||||
.It
|
|
||||||
.Fx
|
|
||||||
local vnode pager support for read-only mappings
|
|
||||||
.El
|
|
||||||
.Sh MOUNT OPTIONS
|
|
||||||
The
|
|
||||||
.Nm
|
|
||||||
filesystem supports standard read-only mount options and the following
|
|
||||||
filesystem-specific option:
|
|
||||||
.Bl -tag -width "device.N=/dev/mdN"
|
|
||||||
.It Cm device.N= Ns Pa path
|
|
||||||
Map one-based on-disk external device slot
|
|
||||||
.Ar N
|
|
||||||
to the disk provider at
|
|
||||||
.Ar path .
|
|
||||||
The slot number is part of the option name, so option order has no effect.
|
|
||||||
Every declared external slot must be supplied exactly once when external blob
|
|
||||||
providers are used.
|
|
||||||
Reusing the primary provider or one external provider for
|
|
||||||
multiple slots is rejected.
|
|
||||||
.El
|
|
||||||
.Pp
|
|
||||||
There is no filesystem-specific
|
|
||||||
.Pa /sbin/mount_erofs
|
|
||||||
utility in this repository.
|
|
||||||
Use the generic
|
|
||||||
.Xr mount 8
|
|
||||||
frontend with
|
|
||||||
.Fl t Cm erofs ;
|
|
||||||
it passes the filesystem-specific option names to
|
|
||||||
.Xr nmount 2 .
|
|
||||||
.Pp
|
|
||||||
If the image has a device table and no
|
|
||||||
.Cm device.N
|
|
||||||
options are supplied, the primary provider is treated as a flatdev image.
|
|
||||||
It
|
|
||||||
must contain every declared device range at its on-disk unified block address.
|
|
||||||
The driver forces every successful mount read-only.
|
|
||||||
An explicit
|
|
||||||
.Fl o Cm rw
|
|
||||||
request therefore still produces a read-only mount; it does not enable writes
|
|
||||||
and is not rejected solely because
|
|
||||||
.Cm rw
|
|
||||||
was requested.
|
|
||||||
Mutating vnode operations fail with
|
|
||||||
.Er EROFS .
|
|
||||||
.Sh EXAMPLES
|
|
||||||
Mount an EROFS image from a disk device:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
mount -t erofs -o ro /dev/da0s1 /mnt
|
|
||||||
.Ed
|
|
||||||
.Pp
|
|
||||||
Mount an EROFS image from a regular file using
|
|
||||||
.Xr mdconfig 8 :
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
mdconfig -a -t vnode -f rootfs.img -u 0
|
|
||||||
mount -t erofs -o ro /dev/md0 /mnt
|
|
||||||
.Ed
|
|
||||||
.Pp
|
|
||||||
Mount a split image with two external blob slots.
|
|
||||||
The deliberately reversed
|
|
||||||
option order demonstrates that slot mapping is deterministic:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
mdconfig -a -t vnode -f primary.img -u 90
|
|
||||||
mdconfig -a -t vnode -f blob1.img -u 91
|
|
||||||
mdconfig -a -t vnode -f blob2.img -u 92
|
|
||||||
mount -t erofs -o ro -o device.2=/dev/md92 \
|
|
||||||
-o device.1=/dev/md91 /dev/md90 /mnt
|
|
||||||
.Ed
|
|
||||||
.Pp
|
|
||||||
Mount a flatdev image containing the primary image followed by all declared
|
|
||||||
unified device ranges:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
mdconfig -a -t vnode -f combined-flatdev.img -u 90
|
|
||||||
mount -t erofs -o ro /dev/md90 /mnt
|
|
||||||
.Ed
|
|
||||||
.Pp
|
|
||||||
Unmount an EROFS filesystem:
|
|
||||||
.Bd -literal -offset indent
|
|
||||||
umount /mnt
|
|
||||||
.Ed
|
|
||||||
.Sh DIAGNOSTICS
|
|
||||||
Error messages are logged via
|
|
||||||
.Xr printf 9
|
|
||||||
when filesystem inconsistencies are detected, such as:
|
|
||||||
.Bl -bullet -compact
|
|
||||||
.It
|
|
||||||
Invalid superblock magic number
|
|
||||||
.It
|
|
||||||
Superblock CRC32C checksum mismatch
|
|
||||||
.It
|
|
||||||
Unsupported compression algorithm
|
|
||||||
.It
|
|
||||||
Invalid inode format
|
|
||||||
.It
|
|
||||||
Invalid or unrepresentable inode timestamps
|
|
||||||
.It
|
|
||||||
Corrupted directory entries
|
|
||||||
.It
|
|
||||||
Compressed extent address arithmetic overflow
|
|
||||||
.It
|
|
||||||
Inline data crossing its inode metadata block or declared backing bounds
|
|
||||||
.It
|
|
||||||
Missing, short, or orphaned external providers
|
|
||||||
.It
|
|
||||||
Malformed or overlapping device-table ranges
|
|
||||||
.El
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr nmount 2 ,
|
|
||||||
.Xr mdconfig 8 ,
|
|
||||||
.Xr mount 8 ,
|
|
||||||
.Xr umount 8 ,
|
|
||||||
.Xr printf 9
|
|
||||||
.Sh HISTORY
|
|
||||||
EROFS was originally developed for Linux by Huawei in 2019.
|
|
||||||
The
|
|
||||||
.Fx
|
|
||||||
implementation first appeared in 2026.
|
|
||||||
.Sh AUTHORS
|
|
||||||
.An Ruicheng Pan
|
|
||||||
.Sh BUGS
|
|
||||||
.Bl -bullet -compact
|
|
||||||
.It
|
|
||||||
The driver is read-only and does not claim support for every future EROFS
|
|
||||||
incompat feature or every dedupe encoding.
|
|
||||||
.It
|
|
||||||
There is no automated kernel regression harness; the repository records
|
|
||||||
.Fx 15
|
|
||||||
manual-test procedures and results.
|
|
||||||
.El
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
# EROFS Feature Status
|
|
||||||
|
|
||||||
This list describes behavior implemented and manually qualified in the
|
|
||||||
FreeBSD 15 module. It is not a claim of complete Linux EROFS feature parity.
|
|
||||||
|
|
||||||
## Filesystem and Metadata
|
|
||||||
|
|
||||||
- Read-only mount/unmount and `statfs`.
|
|
||||||
- Superblock CRC32C, declared image/media bounds, 48-bit block/root-NID decode.
|
|
||||||
- Compact and extended inodes.
|
|
||||||
- Correct compact non-directory `I_NLINK_1` semantics and directory
|
|
||||||
`dot_omitted` semantics.
|
|
||||||
- Linux `new_decode_dev` major/minor decoding followed by FreeBSD `makedev()`.
|
|
||||||
- Superblock-seeded, inode-metadata-derived vnode/NFS generation synchronized
|
|
||||||
with `va_gen`; metadata-identical payload replacement is outside the stale
|
|
||||||
handle guarantee.
|
|
||||||
- NFS export, 64-bit NID file handles, stale-generation and malformed-FID
|
|
||||||
validation.
|
|
||||||
|
|
||||||
## Data Layouts
|
|
||||||
|
|
||||||
- `FLAT_PLAIN` and `FLAT_INLINE` reads.
|
|
||||||
- Inline tails constrained to the inode metadata block and declared backing
|
|
||||||
bounds.
|
|
||||||
- Chunk-based files, chunk indexes, holes, device tables, explicit devices,
|
|
||||||
and flatdev mapping.
|
|
||||||
- LZ4, MicroLZMA, DEFLATE, and ZSTD compressed reads.
|
|
||||||
- Full and compact indexes, partial references, HEAD2/interlaced records,
|
|
||||||
ztailpacking, and fragment-backed compressed data used by qualified images.
|
|
||||||
- Compressed `va_bytes`/`st_blocks` from the complete 48-bit on-disk compressed
|
|
||||||
block count; plain, inline, and chunk files retain logical block rounding.
|
|
||||||
|
|
||||||
## Vnode and Directory Operations
|
|
||||||
|
|
||||||
- `vget`, root lookup, `vfs_hash`, namecache, and `vn_vget_ino` integration.
|
|
||||||
- `lookup`, `readdir`, stable restart cookies, cold nested lookup, and
|
|
||||||
Linux-compatible nonzero final-name padding.
|
|
||||||
- Shared strict validation for dirent arrays, `nameoff`, block bounds, and
|
|
||||||
illegal names.
|
|
||||||
- `getattr`, access checks, `readlink`, `pathconf`, and read-only mutation
|
|
||||||
rejection, including combined special-vnode setattr requests.
|
|
||||||
- FreeBSD 15 `vnode_pager_local_getpages` and compatible async pager entry;
|
|
||||||
`VOP_BMAP` remains explicitly unsupported.
|
|
||||||
|
|
||||||
## Xattrs and ACLs
|
|
||||||
|
|
||||||
- Inline and shared `user.*`, `trusted.*`, and `security.*` attributes.
|
|
||||||
- Shared attributes in primary metadata and metabox containers.
|
|
||||||
- Long-prefix and packed-prefix-table lookup.
|
|
||||||
- FreeBSD user/system namespace exposure and POSIX access/default ACL reads.
|
|
||||||
- Read-only xattr/ACL mutation behavior.
|
|
||||||
|
|
||||||
## Documentation and Validation
|
|
||||||
|
|
||||||
- `erofs(5)` manual page.
|
|
||||||
- Markdown manual tests TC001-TC161, with unresolved cases tracked in
|
|
||||||
`issues/`.
|
|
||||||
- FreeBSD 15 manual reports with fixture hashes and cleanup evidence.
|
|
||||||
- Final explicit-extent ordering, 48-bit allocation, special setattr,
|
|
||||||
`OFF_MAX` directory-cookie, and build-tool failure checks.
|
|
||||||
|
|
||||||
## Build Qualification
|
|
||||||
|
|
||||||
- FreeBSD 15 `amd64` is the only currently validated and accepted target;
|
|
||||||
`src/Makefile` rejects other architectures.
|
|
||||||
- ZSTD support is disabled by default (`WITH_ZSTDIO=0`). Opt-in builds use
|
|
||||||
`WITH_ZSTDIO=1` and require a kernel built with `options ZSTDIO`.
|
|
||||||
|
|
||||||
## Not Implemented or Not Claimed
|
|
||||||
|
|
||||||
- Writable filesystem operations.
|
|
||||||
- A CI pipeline or automated kernel-test harness.
|
|
||||||
- Positive mapped-payload execution of the explicit compressed-extent format;
|
|
||||||
TC146 remains PARTIAL and the fixture limitation is tracked under `issues/`.
|
|
||||||
- Blanket support for every future EROFS incompat feature or every dedupe
|
|
||||||
encoding; only the explicitly qualified fragment/metabox forms are claimed.
|
|
||||||
- Performance guarantees from the manual throughput observations.
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# repo-pre-2 Maintenance Baseline
|
|
||||||
|
|
||||||
## Snapshot Identity
|
|
||||||
|
|
||||||
`repo-pre-2` was created from the tracked `repo-pre-1` tree without copying
|
|
||||||
working-tree-only files or build artifacts.
|
|
||||||
|
|
||||||
```text
|
|
||||||
planning baseline commit: ed47f1b5583a229e372f488b9492d1f6234aae98
|
|
||||||
snapshot creation parent: 109fe74d3fcef107db5869be1d030f4f12d1cfa6
|
|
||||||
snapshot creation commit: 73fa57924b549387400eeeb85354bbbbe770a962
|
|
||||||
repo-pre-1 source tree: 6a5a1a49d4a4e08f6ef1155de240500e63a15365
|
|
||||||
repo-pre-2 snapshot tree: 6a5a1a49d4a4e08f6ef1155de240500e63a15365
|
|
||||||
Linux comparison tree: b79b9a8b62f633e887a8b99075ff9412fabd7f83
|
|
||||||
```
|
|
||||||
|
|
||||||
The matching source and snapshot tree IDs establish byte-for-byte content,
|
|
||||||
file-mode, and path equivalence at snapshot creation. `repo-pre-1` and
|
|
||||||
`src-linux` are read-only references for pre2 work.
|
|
||||||
|
|
||||||
## Phase Scope
|
|
||||||
|
|
||||||
Pre2 phase 1 is L0 mechanical maintenance alignment. It permits only the
|
|
||||||
separately reviewed changes listed below:
|
|
||||||
|
|
||||||
1. Remove stale Linux-only declaration fragments from `src/xattr.h` while
|
|
||||||
preserving every active FreeBSD interface.
|
|
||||||
2. Remove six specified, unreferenced private constants from
|
|
||||||
`src/erofs_defs.h`.
|
|
||||||
3. Rename the private checksum helper in `src/super.c` without changing its
|
|
||||||
signature, body, call position, or behavior.
|
|
||||||
|
|
||||||
Each source change must remain an independent commit. This phase does not add
|
|
||||||
features, fix behavior, move responsibilities between files, reorder data
|
|
||||||
structures, alter ABI, or broadly reformat code.
|
|
||||||
|
|
||||||
## Required FreeBSD Differences
|
|
||||||
|
|
||||||
Linux and FreeBSD EROFS remain independent implementations. The following
|
|
||||||
platform boundaries are intentional and must not be replaced merely to make
|
|
||||||
the source look more similar:
|
|
||||||
|
|
||||||
- FreeBSD VFS, vnode, mount, namecache, pager, and NFS export interfaces.
|
|
||||||
- FreeBSD buffer/cache, GEOM provider, device I/O, locking, and allocation
|
|
||||||
APIs.
|
|
||||||
- FreeBSD xattr, ACL, errno, kernel-module, and `bsd.kmod.mk` conventions.
|
|
||||||
- FreeBSD build gates, including the current amd64 restriction and optional
|
|
||||||
`ZSTDIO` integration.
|
|
||||||
|
|
||||||
Linux naming and layout should be followed only when doing so preserves these
|
|
||||||
native contracts and makes cross-repository review easier.
|
|
||||||
|
|
||||||
## Excluded Work
|
|
||||||
|
|
||||||
This phase does not address vnode ownership after `insmntque()` failure,
|
|
||||||
large-run allocation and `uiomove()` limits, compact pblk validation, 48-bit
|
|
||||||
boundaries, decompressor descriptors, backend ABI, typed errno, xattr parsing,
|
|
||||||
ACL behavior, file splitting, build-system alignment, CI, or test tooling.
|
|
||||||
|
|
||||||
## Validation Status
|
|
||||||
|
|
||||||
Only static snapshot and Git allowlist checks were performed for the
|
|
||||||
initialization commits. No build, QEMU run, test script, smoke test, mount, or
|
|
||||||
runtime feature check was performed. All runtime capabilities therefore remain
|
|
||||||
`NOT RUN` for repo-pre-2 until a later, explicitly authorized validation phase.
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# repo-pre-3 Maintenance Baseline
|
|
||||||
|
|
||||||
## Snapshot Identity
|
|
||||||
|
|
||||||
`repo-pre-3` was created exclusively from the Git-tracked `repo-pre-2` tree.
|
|
||||||
Untracked files, ignored files, build outputs, and working-tree-only content
|
|
||||||
were not copied.
|
|
||||||
|
|
||||||
```text
|
|
||||||
snapshot source commit: 034f409841d2edaf7f140fc7475a357c924a5930
|
|
||||||
snapshot creation commit: 865a702341a82e61ab5ca1d5708a28005277cc0a
|
|
||||||
repo-pre-2 source tree: c28e015c74f4d012dfd070f887fabf75d4d4cb16
|
|
||||||
repo-pre-3 snapshot tree: c28e015c74f4d012dfd070f887fabf75d4d4cb16
|
|
||||||
tracked files per tree: 281
|
|
||||||
```
|
|
||||||
|
|
||||||
The matching tree IDs establish path, file-mode, and blob equivalence at
|
|
||||||
snapshot creation. `repo-pre-2`, `repo-pre-1`, and `src-linux` are read-only
|
|
||||||
references for pre3 work.
|
|
||||||
|
|
||||||
## Phase Scope
|
|
||||||
|
|
||||||
Pre3 is an L1 mechanical naming-alignment stage. It contains four independent
|
|
||||||
source tasks:
|
|
||||||
|
|
||||||
1. Rename `erofs_init_xattr_prefixes` and
|
|
||||||
`erofs_cleanup_xattr_prefixes` to the Linux-like lifecycle names
|
|
||||||
`erofs_xattr_prefixes_init` and `erofs_xattr_prefixes_cleanup`.
|
|
||||||
2. Rename the private ACL helper `erofs_getacl` to `erofs_get_acl`.
|
|
||||||
3. Rename `erofs_close_device` to `erofs_release_device_info` while retaining
|
|
||||||
its FreeBSD implementation.
|
|
||||||
4. Rename the private mount-state destructor `erofs_free_mount` to
|
|
||||||
`erofs_sb_free` while retaining its complete FreeBSD cleanup body.
|
|
||||||
|
|
||||||
Only function names and their closed sets of declarations, definitions, and
|
|
||||||
call sites may change. Signatures, behavior, control flow, ordering, locking,
|
|
||||||
ownership, error handling, and file responsibilities must remain unchanged.
|
|
||||||
|
|
||||||
## Required FreeBSD Differences
|
|
||||||
|
|
||||||
- Xattr-prefix helpers continue to use `struct erofs_mount *`, not Linux
|
|
||||||
`struct super_block *`.
|
|
||||||
- ACL handling continues to use FreeBSD `struct vnode *`, `struct acl *`, and
|
|
||||||
integer errno conventions.
|
|
||||||
- Device teardown continues to release GEOM consumers, vnode references, and
|
|
||||||
cdev references in the existing order and under the existing locking rules.
|
|
||||||
It must not adopt the Linux callback signature or ownership model.
|
|
||||||
- Mount-state teardown continues to release all FreeBSD GEOM and private
|
|
||||||
filesystem state. A Linux-like name does not make the implementations or
|
|
||||||
lifecycle contracts interchangeable.
|
|
||||||
|
|
||||||
## Excluded Work
|
|
||||||
|
|
||||||
Pre3 does not include feature changes, correctness fixes, ABI changes, codec
|
|
||||||
work, xattr or ACL behavior changes, function reordering, structure layout
|
|
||||||
changes, file splitting, build-system changes, formatting cleanup, or repairs
|
|
||||||
to earlier planning and snapshot material.
|
|
||||||
|
|
||||||
## Git Workflow
|
|
||||||
|
|
||||||
The snapshot, this baseline document, and each of the four rename batches are
|
|
||||||
separate commits. Every commit must be pushed immediately to `xdm main` and
|
|
||||||
must not be squashed with another batch. Before each commit, its staged paths
|
|
||||||
must be checked against the task-specific allowlist. After each push, local
|
|
||||||
`HEAD`, `xdm/main`, and remote `main` must identify the same commit.
|
|
||||||
|
|
||||||
## Validation Status
|
|
||||||
|
|
||||||
Only static snapshot-equivalence, path-allowlist, Git-state, and documentation
|
|
||||||
checks were performed for pre3 initialization.
|
|
||||||
|
|
||||||
```text
|
|
||||||
build: NOT RUN
|
|
||||||
QEMU: NOT RUN
|
|
||||||
test scripts: NOT RUN
|
|
||||||
smoke tests: NOT RUN
|
|
||||||
mount/runtime: NOT RUN
|
|
||||||
feature validation: NOT RUN
|
|
||||||
```
|
|
||||||
|
|
||||||
No compile-time or runtime PASS is claimed by this document. Existing reports
|
|
||||||
copied from `repo-pre-2` are historical material and are not fresh validation
|
|
||||||
of `repo-pre-3`.
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
# Pre3 Smoke Test Report - 2026-08-12
|
|
||||||
|
|
||||||
## Result
|
|
||||||
|
|
||||||
The `repo-pre-3` plain/LZ4 differential smoke test **PASSed** within the scope documented below.
|
|
||||||
|
|
||||||
| Field | Value |
|
|
||||||
|---|---|
|
|
||||||
| Run ID | `20260812T110037.575683Z-693361-ac21acee` |
|
|
||||||
| Process exit code | `0` |
|
|
||||||
| Guest return code | `0` |
|
|
||||||
| Runner stages | `12/12 passed` |
|
|
||||||
| Elapsed time | `18m51s` |
|
|
||||||
| DUT outer commit | `1a2361bfae2f6b4e7fc4c89d97d05f44553a5ba7` (`1a2361b`) |
|
|
||||||
| DUT path tree | `902a32fbfc1274d4404174346953d19e41c61f1f` |
|
|
||||||
| DUT content SHA256 | `07aa856f0c0d9d0d084dbcb5d743cf4831a7f2ab884b51941db7d1840b248c60` |
|
|
||||||
| KLD SHA256 | `59650f03029afc31658dcf3386105d001122d7702b8144e7c5925d9d9ed4accb` |
|
|
||||||
| Base image SHA256 | `67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef` |
|
|
||||||
| Base image mode | `0444`, unchanged before and after |
|
|
||||||
|
|
||||||
Primary evidence:
|
|
||||||
|
|
||||||
- [result.json](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/result.json)
|
|
||||||
- [summary.txt](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/summary.txt)
|
|
||||||
- [guest evidence directory](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/guest-evidence)
|
|
||||||
- [guest-result.json](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/guest-evidence/guest-result.json)
|
|
||||||
|
|
||||||
## Invocation
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./test.sh --dut /work/erofs-freebsd-pre/repo-pre-3 \
|
|
||||||
--base-image /work/tests-dev/lfs/freebsd-15-dev-src-20260811.bp \
|
|
||||||
--duration 10 \
|
|
||||||
--output demo-result/repo-pre-3-smoke-20260812
|
|
||||||
```
|
|
||||||
|
|
||||||
Evidence root:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/
|
|
||||||
```
|
|
||||||
|
|
||||||
## PASS Scope
|
|
||||||
|
|
||||||
The successful run covered:
|
|
||||||
|
|
||||||
- FreeBSD guest boot and SSH readiness.
|
|
||||||
- DUT build with `WITH_ZSTDIO=0` and loading the exact generated `erofs.ko`.
|
|
||||||
- Creation and use of plain and LZ4 EROFS fixtures.
|
|
||||||
- Attach, mount, differential workload, unmount, and fixture cleanup.
|
|
||||||
- Four workers per fixture for five seconds each.
|
|
||||||
- Differential random, aligned, unaligned, full-file, and EOF reads.
|
|
||||||
- Directory enumeration, symbolic-link reads, and `fadvise` operations.
|
|
||||||
- Host and guest resource cleanup after the workload.
|
|
||||||
|
|
||||||
The guest-side stages and fixture identities are recorded in [stages.txt](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/guest-evidence/stages.txt) and [scenarios.txt](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/guest-evidence/scenarios.txt). Per-worker evidence is available in the same guest evidence directory.
|
|
||||||
|
|
||||||
## SKIPPED And Non-Claims
|
|
||||||
|
|
||||||
The following tests were **SKIPPED** and have no execution evidence in this run:
|
|
||||||
|
|
||||||
| Test | Area | Status |
|
|
||||||
|---|---|---|
|
|
||||||
| `TC079` | xattr prefix initialization, lookup, and cleanup | `SKIPPED` |
|
|
||||||
| `TC138` | ACL parsing and error paths | `SKIPPED` |
|
|
||||||
| `TC099` | multidevice mount and release paths | `SKIPPED` |
|
|
||||||
|
|
||||||
This report therefore does **not** claim that xattr prefix handling, ACL behavior, multidevice behavior, ZSTD, LZMA, DEFLATE, or the full feature/regression suite passed. The PASS result is limited to the plain/LZ4 differential smoke scope listed above.
|
|
||||||
|
|
||||||
## Integrity And Cleanup
|
|
||||||
|
|
||||||
- The DUT content hash, commit, and tree were identical before and after the run; the test did not modify `repo-pre-3`.
|
|
||||||
- The read-only base image remained mode `0444` with the same SHA256 before and after the run.
|
|
||||||
- New QEMU PID `693836` exited gracefully.
|
|
||||||
- Test port `10000` was released.
|
|
||||||
- The qcow2 overlay was deleted and the port lock became available.
|
|
||||||
- Guard PID `26318` and guard port `9222` retained the same process identity, start time, and command hash.
|
|
||||||
- The generated result directory under `tests-dev` is evidence only and was not committed.
|
|
||||||
|
|
||||||
## Honesty Review
|
|
||||||
|
|
||||||
The post-run honesty audit **PASSed**. It found no concealed source fix, result substitution, or exaggerated coverage claim. The guest log filename `repo22-build.txt` and related `repo22` stage labels are inherited labels in the test harness; they do not identify the DUT. The DUT is independently bound to `repo-pre-3` by the recorded commit, path tree, content hash, archived source, and generated KLD hash.
|
|
||||||
|
|
||||||
The complete machine-readable record remains authoritative for details not reproduced here: [result.json](/work/tests-dev/erofsstress/demo-result/repo-pre-3-smoke-20260812/20260812T110037.575683Z-693361-ac21acee/result.json).
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
# Pre5 Extraction Baseline
|
|
||||||
|
|
||||||
## Repository Baseline
|
|
||||||
|
|
||||||
- Outer starting commit: `6421919003ecfab5317dfa70959ab81cd9bbc990`
|
|
||||||
- Starting `repo-pre-5` tree: `f99462eee8898af209332ef202f8da07f2dd567e`
|
|
||||||
- Starting `repo-pre-5/src/super.c` blob: `c150d795df42ae4136fbd6e74c3b88903341b05a`
|
|
||||||
- Execution target: the existing `repo-pre-5` directory
|
|
||||||
- Source allowlist for the later extraction commits: `repo-pre-5/src/super.c`
|
|
||||||
|
|
||||||
The fixed tree and blob identifiers above were read from Git before this
|
|
||||||
document was created. Pre5 works directly on `repo-pre-5`; it does not create
|
|
||||||
another snapshot.
|
|
||||||
|
|
||||||
## Stage Scope
|
|
||||||
|
|
||||||
Pre5 is an L2-S private cleanup responsibility extraction stage. It has two
|
|
||||||
source tasks:
|
|
||||||
|
|
||||||
1. Extract the existing extra-device cleanup from `erofs_sb_free()` into
|
|
||||||
`static void erofs_free_dev_context(struct erofs_mount *em)`.
|
|
||||||
2. Extract the existing metabox and packed-inode cleanup from
|
|
||||||
`erofs_sb_free()` into
|
|
||||||
`static void erofs_drop_internal_inodes(struct erofs_mount *em)`.
|
|
||||||
|
|
||||||
Both tasks are statement movement only. They must preserve FreeBSD GEOM,
|
|
||||||
vnode, allocation, and ownership semantics. They must not change behavior,
|
|
||||||
ABI, features, error handling, locking, logging, conditions, release calls, or
|
|
||||||
object ownership.
|
|
||||||
|
|
||||||
## Protected Paths
|
|
||||||
|
|
||||||
The following paths must remain unchanged during Pre5 execution:
|
|
||||||
|
|
||||||
- `repo-pre-3/`
|
|
||||||
- `repo-pre-2/`
|
|
||||||
- `repo-pre-1/`
|
|
||||||
- `src-linux/`
|
|
||||||
- `planning/reject/`
|
|
||||||
- existing reports and other planning stages
|
|
||||||
|
|
||||||
Except for this baseline document, no path outside
|
|
||||||
`repo-pre-5/src/super.c` belongs in the Pre5 source commits.
|
|
||||||
|
|
||||||
## Cleanup-Order Invariant
|
|
||||||
|
|
||||||
The effective cleanup order must remain exactly:
|
|
||||||
|
|
||||||
```text
|
|
||||||
xattr prefixes
|
|
||||||
-> metabox
|
|
||||||
-> packed inode
|
|
||||||
-> extra devices in reverse order
|
|
||||||
-> primary device
|
|
||||||
-> mount state
|
|
||||||
```
|
|
||||||
|
|
||||||
The extraction must not add pointer clearing, conditions, assertions, logs,
|
|
||||||
locks, return values, error handling, or header declarations.
|
|
||||||
|
|
||||||
## Commit and Push Discipline
|
|
||||||
|
|
||||||
Each Pre5 commit must contain one planned logical task and must be pushed
|
|
||||||
immediately to `xdm main`. The commits must not be squashed. Execution must
|
|
||||||
stop if a push fails or if local, tracking, and remote commit identities
|
|
||||||
diverge.
|
|
||||||
|
|
||||||
## Validation Status at Baseline
|
|
||||||
|
|
||||||
| Validation item | Status |
|
|
||||||
|---|---|
|
|
||||||
| Static Git baseline capture | RECORDED |
|
|
||||||
| Source extraction tasks | NOT RUN |
|
|
||||||
| Build with `WITH_ZSTDIO=0` | NOT RUN |
|
|
||||||
| Build with `WITH_ZSTDIO=1` | NOT RUN |
|
|
||||||
| QEMU smoke testing | NOT RUN |
|
|
||||||
| Manual or automated tests | NOT RUN |
|
|
||||||
|
|
||||||
No build, QEMU run, feature validation, regression test, or runtime result is
|
|
||||||
claimed by this document.
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
# Pre5 Completion Report
|
|
||||||
|
|
||||||
Date: 2026-08-12
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
| Area | Result | Notes |
|
|
||||||
|---|---|---|
|
|
||||||
| Planned source extraction | PASS | Both private cleanup helpers are present in `repo-pre-5/src/super.c`. |
|
|
||||||
| Static correctness review | PASS | No High or Medium findings; statement order and FreeBSD cleanup behavior are preserved. |
|
|
||||||
| Commit recoverability | PASS after correction | The initial split commits were non-destructively reverted and replaced by one independently revertible atomic source commit. |
|
|
||||||
| `WITH_ZSTDIO=0` build | PASS | Exit code 0, zero warnings, zero errors. |
|
|
||||||
| Module load | NOT RUN | The produced `erofs.ko` was not loaded. |
|
|
||||||
| QEMU functional testing | NOT RUN | No functional or regression test was run for Pre5. |
|
|
||||||
| Pre5 smoke test | DEFERRED | Deferred for a combined Pre5/Pre6 smoke run. |
|
|
||||||
|
|
||||||
Pre5 is complete for its planned source changes, static review, and required
|
|
||||||
build gate. This report does not claim runtime, feature, regression, or smoke
|
|
||||||
test coverage.
|
|
||||||
|
|
||||||
The final Pre5 source commit is
|
|
||||||
`4535cccaf1ca1837f0a2d1cca526e5f138a23c6d`. This report is created after that
|
|
||||||
commit and, when committed, its documentation commit will therefore follow the
|
|
||||||
final source commit.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
Pre5 directly modified `repo-pre-5`; no new repository snapshot was created.
|
|
||||||
The starting planning commit was:
|
|
||||||
|
|
||||||
```text
|
|
||||||
6421919003ecfab5317dfa70959ab81cd9bbc990
|
|
||||||
docs: plan repo-pre-5 cleanup extraction phase
|
|
||||||
```
|
|
||||||
|
|
||||||
The baseline documentation commit was:
|
|
||||||
|
|
||||||
```text
|
|
||||||
0666800fa529a8869757da85f2e69b8e1dd2c9f6
|
|
||||||
docs: record pre5 extraction baseline
|
|
||||||
```
|
|
||||||
|
|
||||||
The baseline recorded the following source identity:
|
|
||||||
|
|
||||||
```text
|
|
||||||
repo-pre-5/src/super.c blob:
|
|
||||||
c150d795df42ae4136fbd6e74c3b88903341b05a
|
|
||||||
```
|
|
||||||
|
|
||||||
The source scope was limited to extracting two existing cleanup regions from
|
|
||||||
`erofs_sb_free()` into private helpers. No feature, ABI, error handling,
|
|
||||||
locking, logging, ownership, or cleanup policy change was intended.
|
|
||||||
|
|
||||||
## Final Implementation
|
|
||||||
|
|
||||||
The final implementation is in [`src/super.c`](../src/super.c).
|
|
||||||
|
|
||||||
### Extra-device cleanup
|
|
||||||
|
|
||||||
`erofs_free_dev_context()` is a `static void` helper with exactly one
|
|
||||||
definition and one call. It contains only the existing extra-device cleanup:
|
|
||||||
|
|
||||||
```c
|
|
||||||
static void
|
|
||||||
erofs_free_dev_context(struct erofs_mount *em)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (em->devs != NULL) {
|
|
||||||
for (i = em->extra_devices; i > 0; --i)
|
|
||||||
erofs_release_device_info(&em->devs[i - 1]);
|
|
||||||
free(em->devs, M_EROFS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The reverse close order is unchanged. The primary device remains outside this
|
|
||||||
helper and is still released separately by `erofs_sb_free()`.
|
|
||||||
|
|
||||||
### Internal-inode cleanup
|
|
||||||
|
|
||||||
`erofs_drop_internal_inodes()` is a `static void` helper with exactly one
|
|
||||||
definition and one call. It contains only the existing metabox and packed
|
|
||||||
inode releases:
|
|
||||||
|
|
||||||
```c
|
|
||||||
static void
|
|
||||||
erofs_drop_internal_inodes(struct erofs_mount *em)
|
|
||||||
{
|
|
||||||
if (em->metabox_en != NULL)
|
|
||||||
free(em->metabox_en, M_EROFS);
|
|
||||||
if (em->packed_inode != NULL)
|
|
||||||
free(em->packed_inode, M_EROFS);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This remains a FreeBSD allocation cleanup path. It does not copy Linux
|
|
||||||
`iput()` or Linux inode-lifecycle semantics.
|
|
||||||
|
|
||||||
### Preserved cleanup order
|
|
||||||
|
|
||||||
The effective cleanup order remains:
|
|
||||||
|
|
||||||
```text
|
|
||||||
xattr prefixes
|
|
||||||
-> metabox
|
|
||||||
-> packed inode
|
|
||||||
-> extra devices in reverse order
|
|
||||||
-> primary device
|
|
||||||
-> mount state
|
|
||||||
```
|
|
||||||
|
|
||||||
The final caller is:
|
|
||||||
|
|
||||||
```c
|
|
||||||
static void
|
|
||||||
erofs_sb_free(struct erofs_mount *em)
|
|
||||||
{
|
|
||||||
if (em == NULL)
|
|
||||||
return;
|
|
||||||
erofs_xattr_prefixes_cleanup(em);
|
|
||||||
erofs_drop_internal_inodes(em);
|
|
||||||
erofs_free_dev_context(em);
|
|
||||||
erofs_release_device_info(&em->dif0);
|
|
||||||
free(em, M_EROFS);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Static expansion of both helpers produces the baseline statement sequence.
|
|
||||||
No condition, loop direction, release function, pointer clearing, lock, errno,
|
|
||||||
log message, return value, or ownership rule was added or changed.
|
|
||||||
|
|
||||||
## Commit Timeline
|
|
||||||
|
|
||||||
| Commit | Purpose | Result |
|
|
||||||
|---|---|---|
|
|
||||||
| `6421919` | Establish the Pre5 execution plan | Baseline planning point. |
|
|
||||||
| `0666800` | Record the source baseline and validation status | Documentation only. |
|
|
||||||
| `52dca2e` | Initially extract `erofs_free_dev_context()` | Static behavior correct. |
|
|
||||||
| `e9b9fb2` | Initially extract `erofs_drop_internal_inodes()` | Static behavior correct. |
|
|
||||||
| `c406813` | Revert `e9b9fb2` | Non-destructively removed the second helper first. |
|
|
||||||
| `20733bd` | Revert `52dca2e` | Restored the exact baseline `super.c` blob. |
|
|
||||||
| `4535ccc` | Atomically introduce both cleanup helpers | Final source implementation. |
|
|
||||||
|
|
||||||
The initial two source commits were behaviorally correct. The static audit
|
|
||||||
found a commit-organization defect: after `e9b9fb2`, the earlier `52dca2e`
|
|
||||||
could not be independently reverted from the final HEAD without conflict
|
|
||||||
because both commits edited the same tightly coupled `erofs_sb_free()` region.
|
|
||||||
|
|
||||||
No history rewrite or destructive reset was used. The correction was:
|
|
||||||
|
|
||||||
1. Revert `e9b9fb2` with `c406813`.
|
|
||||||
2. Revert `52dca2e` with `20733bd`.
|
|
||||||
3. Confirm that `super.c` returned to baseline blob
|
|
||||||
`c150d795df42ae4136fbd6e74c3b88903341b05a`.
|
|
||||||
4. Reintroduce both helpers in atomic commit `4535ccc`.
|
|
||||||
|
|
||||||
The final `super.c` blob is:
|
|
||||||
|
|
||||||
```text
|
|
||||||
03b92560bb5ef01f322b0d052f84bc3c577ef829
|
|
||||||
```
|
|
||||||
|
|
||||||
This is byte-for-byte identical to the correct source state at `e9b9fb2`.
|
|
||||||
The final commit `4535ccc` can be reverted without conflict and restores the
|
|
||||||
baseline blob.
|
|
||||||
|
|
||||||
The original plan preferred one source task per commit. That rule was adjusted
|
|
||||||
because the two extractions share one cleanup sequence and one caller region;
|
|
||||||
separate commits weakened independent rollback despite preserving behavior.
|
|
||||||
One atomic source commit provides a clearer and mechanically verifiable
|
|
||||||
rollback boundary without changing the planned source result.
|
|
||||||
|
|
||||||
## Static Review Evidence
|
|
||||||
|
|
||||||
The final independent static review result was PASS with no High or Medium
|
|
||||||
findings.
|
|
||||||
|
|
||||||
Verified properties:
|
|
||||||
|
|
||||||
- Only `repo-pre-5/src/super.c` differs from the source baseline.
|
|
||||||
- Both helpers are `static void` and each has one definition and one call.
|
|
||||||
- Extra devices are still released in reverse order before `em->devs` is
|
|
||||||
freed.
|
|
||||||
- Metabox cleanup still precedes packed-inode cleanup.
|
|
||||||
- The primary device remains a separate release after the extra-device
|
|
||||||
context.
|
|
||||||
- The mount state remains the final allocation released.
|
|
||||||
- Expanding both helpers recovers the original cleanup statement sequence.
|
|
||||||
- No header, exported interface, ABI, feature, condition, lock, errno, log, or
|
|
||||||
ownership change was introduced.
|
|
||||||
- No deferred correctness, codec, descriptor, formatting, or feature work was
|
|
||||||
mixed into Pre5.
|
|
||||||
- `repo-pre-1/`, `repo-pre-2/`, `repo-pre-3/`, `src-linux/`, planning files,
|
|
||||||
reject records, and earlier reports remained protected from source changes.
|
|
||||||
|
|
||||||
The source result therefore satisfies the intended L2-S responsibility
|
|
||||||
extraction while preserving the necessary FreeBSD cleanup implementation.
|
|
||||||
|
|
||||||
## Build Evidence
|
|
||||||
|
|
||||||
The required build gate was executed in the existing FreeBSD 15 VM with PID
|
|
||||||
`26318`. No new VM was started for this build.
|
|
||||||
|
|
||||||
Command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
FREEBSD_SRC=/root/pre5-build-gate-20260812T125645Z/freebsd-src \
|
|
||||||
WITH_ZSTDIO=0 ./build.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Result:
|
|
||||||
|
|
||||||
| Evidence | Value |
|
|
||||||
|---|---|
|
|
||||||
| Exit code | `0` |
|
|
||||||
| Compiler warnings | `0` |
|
|
||||||
| Compiler errors | `0` |
|
|
||||||
| Build log | `repo-pre-5/build/pre5-zstdio0-20260812T125645Z/build.log` |
|
|
||||||
| Module | `repo-pre-5/build/pre5-zstdio0-20260812T125645Z/erofs.ko` |
|
|
||||||
| Module size | `78,248` bytes |
|
|
||||||
| Module SHA256 | `0a2928a711715a22dfe243a536f514395acd52af3cec5515bd4bb003e42a14ac` |
|
|
||||||
|
|
||||||
The build artifacts are under the ignored `repo-pre-5/build/` directory and
|
|
||||||
must not be committed. The module was not loaded, and the build result alone
|
|
||||||
does not establish runtime behavior.
|
|
||||||
|
|
||||||
## Not Run And Deferred
|
|
||||||
|
|
||||||
| Item | Status | Meaning |
|
|
||||||
|---|---|---|
|
|
||||||
| Load produced `erofs.ko` | NOT RUN | Module load and unload behavior were not checked. |
|
|
||||||
| QEMU functional testing | NOT RUN | No functional test VM run was performed for Pre5. |
|
|
||||||
| Feature or regression suite | NOT RUN | No feature-completeness claim is made. |
|
|
||||||
| Pre5 standalone smoke test | DEFERRED | Deferred by user direction and risk assessment. |
|
|
||||||
| Combined Pre5/Pre6 smoke test | REQUIRED LATER | Must be performed after Pre6 before claiming runtime coverage. |
|
|
||||||
|
|
||||||
The Pre5 changes only extract existing private cleanup statements, and the
|
|
||||||
static review plus build gate found no source or compiler issue requiring an
|
|
||||||
immediate standalone smoke run. To avoid duplicating a relatively expensive VM
|
|
||||||
cycle, the smoke test is deferred and will be combined with Pre6.
|
|
||||||
|
|
||||||
The combined Pre5/Pre6 smoke run must cover at least:
|
|
||||||
|
|
||||||
1. Plain and LZ4 basic build, module load, mount, read, readdir, unmount, and
|
|
||||||
cleanup.
|
|
||||||
2. `TC099` multi-device success, missing-device failure, and device cleanup.
|
|
||||||
3. A packed-inode/metabox fixture mount and unmount path that exercises
|
|
||||||
internal-inode cleanup.
|
|
||||||
|
|
||||||
None of these deferred checks is claimed as passed by this report.
|
|
||||||
|
|
||||||
## Residual Risk
|
|
||||||
|
|
||||||
- The compiled module has not been loaded, so loader, symbol-resolution, and
|
|
||||||
unload behavior remain unverified for the final source commit.
|
|
||||||
- Failure and partial-initialization paths have only been reviewed statically.
|
|
||||||
- Multi-device cleanup has not been exercised at runtime after extracting
|
|
||||||
`erofs_free_dev_context()`.
|
|
||||||
- Packed-inode and metabox cleanup has not been exercised at runtime after
|
|
||||||
extracting `erofs_drop_internal_inodes()`.
|
|
||||||
- `WITH_ZSTDIO=1` was not built in this stage.
|
|
||||||
- No QEMU smoke, feature suite, stress test, or regression test has been run
|
|
||||||
specifically against the final Pre5 source state.
|
|
||||||
|
|
||||||
These risks are accepted for the current stage and are carried into the
|
|
||||||
combined Pre5/Pre6 smoke gate. Until that gate runs, Pre5 should be described
|
|
||||||
as static-review PASS and `WITH_ZSTDIO=0` build PASS, not runtime PASS.
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
# Pre6 Initialization Baseline
|
|
||||||
|
|
||||||
## Repository Baseline
|
|
||||||
|
|
||||||
- Outer starting commit: `bfed0431693e7798bdecacd78b7e6258c2d93c5a`
|
|
||||||
- Starting `repo-pre-6` tree: `b4a40164394b378adc947d6ad14dc7c845e79b2c`
|
|
||||||
- Starting `repo-pre-6/src/super.c` blob: `03b92560bb5ef01f322b0d052f84bc3c577ef829`
|
|
||||||
- Execution target: the existing `repo-pre-6` directory
|
|
||||||
- Source allowlist for later extraction commits: `repo-pre-6/src/super.c`
|
|
||||||
|
|
||||||
The tree and blob identities above were read from Git before this document was
|
|
||||||
created. Pre6 works directly on `repo-pre-6`; it does not create another source
|
|
||||||
snapshot.
|
|
||||||
|
|
||||||
## Stage Scope
|
|
||||||
|
|
||||||
Pre6 is an L2-I private mount-initialization responsibility extraction stage.
|
|
||||||
It contains three helper tasks:
|
|
||||||
|
|
||||||
1. Extract one decoded external-device initialization block into
|
|
||||||
`static int erofs_init_device(...)`.
|
|
||||||
2. Extract packed-carrier initialization into
|
|
||||||
`static int erofs_init_packed_inode(struct erofs_mount *em)`.
|
|
||||||
3. Extract metabox initialization into
|
|
||||||
`static int erofs_init_metabox_inode(struct erofs_mount *em)`.
|
|
||||||
|
|
||||||
These tasks move existing statements into private helpers. They must not change
|
|
||||||
features, behavior, public interfaces, error handling, allocation, cleanup,
|
|
||||||
logging, locking, GEOM operations, or object ownership.
|
|
||||||
|
|
||||||
## Source Commit Strategy
|
|
||||||
|
|
||||||
The source work is delivered in two commits:
|
|
||||||
|
|
||||||
1. One independent commit for `erofs_init_device()`.
|
|
||||||
2. One atomic commit for `erofs_init_packed_inode()` and
|
|
||||||
`erofs_init_metabox_inode()`.
|
|
||||||
|
|
||||||
Packed and metabox initialization remain one ownership unit because their
|
|
||||||
blocks are adjacent and a fragment-backed metabox can depend on the packed
|
|
||||||
carrier. No intermediate commit may contain only one internal-inode helper.
|
|
||||||
|
|
||||||
Each commit, including this baseline commit, must be pushed immediately to
|
|
||||||
`xdm main`. Execution must stop if local HEAD, `xdm/main`, and remote `main`
|
|
||||||
do not agree after a push.
|
|
||||||
|
|
||||||
## Protected Paths
|
|
||||||
|
|
||||||
The following paths must remain unchanged during Pre6 execution:
|
|
||||||
|
|
||||||
- `repo-pre-1/`
|
|
||||||
- `repo-pre-2/`
|
|
||||||
- `repo-pre-3/`
|
|
||||||
- `repo-pre-5/`
|
|
||||||
- `src-linux/`
|
|
||||||
- `planning/reject/`
|
|
||||||
- `1-code-similarity-review/`
|
|
||||||
- existing planning documents and reports
|
|
||||||
|
|
||||||
Except for Pre6 documents under `repo-pre-6/docs/`, no path outside
|
|
||||||
`repo-pre-6/src/super.c` belongs in the planned source commits.
|
|
||||||
|
|
||||||
## Behavior-Preservation Invariants
|
|
||||||
|
|
||||||
- Preserve the order of every moved statement and every helper call.
|
|
||||||
- Preserve all conditions, loop direction, values, types, casts, and return
|
|
||||||
values.
|
|
||||||
- Preserve every errno and log message without translation or normalization.
|
|
||||||
- Preserve allocations, frees, NULL assignments, and failure paths.
|
|
||||||
- Preserve the current owner and lifetime of every buffer, device, inode, and
|
|
||||||
mount resource.
|
|
||||||
- Keep `erofs_open_device()` unchanged as the FreeBSD GEOM open transaction.
|
|
||||||
- Keep external-device slot lookup and ascending iteration in
|
|
||||||
`erofs_scan_devices()`.
|
|
||||||
- Keep packed inode initialization before metabox inode initialization.
|
|
||||||
- Keep `erofs_mountfs()` as the common failure owner that calls
|
|
||||||
`erofs_sb_free()`.
|
|
||||||
- Add no rollback, validation, cleanup, logging, locking, or defensive changes.
|
|
||||||
- Keep all new helpers private and add no header declarations.
|
|
||||||
|
|
||||||
If an extraction requires a behavior, ownership, ordering, or errno change,
|
|
||||||
execution must stop instead of expanding Pre6 scope.
|
|
||||||
|
|
||||||
## Validation Status at Baseline
|
|
||||||
|
|
||||||
| Validation item | Status |
|
|
||||||
|---|---|
|
|
||||||
| Static Git baseline capture | RECORDED |
|
|
||||||
| Device initialization extraction | NOT RUN |
|
|
||||||
| Packed and metabox initialization extraction | NOT RUN |
|
|
||||||
| Static equivalence and independent revert gates | NOT RUN |
|
|
||||||
| Build with `WITH_ZSTDIO=0` | NOT RUN |
|
|
||||||
| Plain/LZ4 smoke test | NOT RUN |
|
|
||||||
| Complete `TC099` multi-device smoke test | NOT RUN |
|
|
||||||
| Positive `TC142` metabox smoke test | NOT RUN |
|
|
||||||
| Other build, QEMU, or runtime tests | NOT RUN |
|
|
||||||
|
|
||||||
No source extraction, build, QEMU run, feature validation, regression test, or
|
|
||||||
runtime result is claimed by this baseline document.
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# Pre7 Helper-Alignment Baseline
|
|
||||||
|
|
||||||
## Repository Baseline
|
|
||||||
|
|
||||||
- Execution-start commit: `3f5f783b9f316af6d3887421251cc79909aed934`
|
|
||||||
- Starting `repo-pre-7` tree: `909ffaa0f586a51933f4220a8fe67d963d5b1dff`
|
|
||||||
- Starting `repo-pre-6` tree: `909ffaa0f586a51933f4220a8fe67d963d5b1dff`
|
|
||||||
- Starting `repo-pre-7/src/internal.h` blob: `253a30a595f9740ce97de865cc6f255f8eda2b74`
|
|
||||||
- Starting `repo-pre-7/src/inode.c` blob: `c753c14fdc48ae53e6dd2554cb9dc4a5b8a6c569`
|
|
||||||
- Starting `repo-pre-7/src/xattr.c` blob: `cef4db2a8d03be028c0344941cea60def9cd84ce`
|
|
||||||
- Execution target: the existing `repo-pre-7` directory
|
|
||||||
|
|
||||||
The tracked `repo-pre-7` baseline is an exact snapshot of `repo-pre-6` at the
|
|
||||||
execution-start commit. The identities above were read from Git objects at
|
|
||||||
that commit, not inferred from the live worktree.
|
|
||||||
|
|
||||||
Uncommitted changes were already present in `repo-pre-7/src/internal.h` and
|
|
||||||
`repo-pre-7/src/inode.c` when this document was written. This baseline does
|
|
||||||
not assess, validate, or claim completion of those changes.
|
|
||||||
|
|
||||||
## Exact Source Scope
|
|
||||||
|
|
||||||
Pre7 contains exactly two source tasks:
|
|
||||||
|
|
||||||
1. Rename the private inode-location helper from
|
|
||||||
`erofs_nid_to_offset()` to `erofs_iloc()` in
|
|
||||||
`repo-pre-7/src/internal.h` and `repo-pre-7/src/inode.c`. This is an
|
|
||||||
identifier-only alignment; the FreeBSD signature, implementation,
|
|
||||||
callers, metabox handling, overflow checks, and failure behavior remain
|
|
||||||
unchanged.
|
|
||||||
2. Extract the private `erofs_xattr_prefix()` mapping helper from
|
|
||||||
`erofs_xattr_namespace_prefix()` in `repo-pre-7/src/xattr.c`. The existing
|
|
||||||
wrapper retains FreeBSD namespace validation, namespace matching, errno
|
|
||||||
selection, and all existing get/list call sites.
|
|
||||||
|
|
||||||
No other source file, helper cleanup, behavior change, public interface
|
|
||||||
change, formatting pass, or deferred planning item belongs in Pre7.
|
|
||||||
|
|
||||||
## Validation Status
|
|
||||||
|
|
||||||
Per the current execution instruction, this baseline-recording step performs
|
|
||||||
no build or test activity. Historical Pre6 evidence is not a Pre7 result.
|
|
||||||
|
|
||||||
| Validation item | Status |
|
|
||||||
|---|---|
|
|
||||||
| Pre7 source implementation validation | NOT RUN |
|
|
||||||
| Static reference and behavior-matrix checks | NOT RUN |
|
|
||||||
| Independent source-commit revert checks | NOT RUN |
|
|
||||||
| `WITH_ZSTDIO=0` build | NOT RUN |
|
|
||||||
| QEMU smoke testing | NOT RUN |
|
|
||||||
| Manual or automated runtime tests | NOT RUN |
|
|
||||||
| CI testing | SKIPPED |
|
|
||||||
|
|
||||||
This is an implementation baseline only. It is not a completion report and
|
|
||||||
does not claim that either Pre7 source task is complete or correct.
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
# Pre8 Responsibility-Alignment Baseline
|
|
||||||
|
|
||||||
## Repository Identity
|
|
||||||
|
|
||||||
The following identities were read directly from Git objects at execution-start
|
|
||||||
commit `475b62437f89a8a98e0e3a1d1628481768525cb2`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
execution-start commit: 475b62437f89a8a98e0e3a1d1628481768525cb2
|
|
||||||
execution-start tree: 3f0bc6be8324446440ce578f03d892c95f73591c
|
|
||||||
repo-pre-7 tree: b8f9af2cd55225c4348b79ff5910ae6fc83cd517
|
|
||||||
repo-pre-8 tree: b8f9af2cd55225c4348b79ff5910ae6fc83cd517
|
|
||||||
```
|
|
||||||
|
|
||||||
The equal `repo-pre-7` and `repo-pre-8` tree identities establish that
|
|
||||||
`repo-pre-8` is an exact tracked snapshot of `repo-pre-7` at the execution
|
|
||||||
start. This relationship is based on Git object identities, not a live
|
|
||||||
worktree comparison.
|
|
||||||
|
|
||||||
Relevant source identities at the same commit are:
|
|
||||||
|
|
||||||
```text
|
|
||||||
mode blob path
|
|
||||||
100644 e06822e363d9122a39256494bde7d12cfea1f7c9 repo-pre-8/src/decompressor.c
|
|
||||||
100644 ff595fe009679a4e950eb3743b2f152fac4aad31 repo-pre-8/src/decompressor_lzma.c
|
|
||||||
100644 f3e48cd2016608aaf84ed5e80151782a6c5513f7 repo-pre-8/src/decompressor_deflate.c
|
|
||||||
100644 23756af263ceb148ca50fbb8cd1ae80ba3fac4cd repo-pre-8/src/decompressor_zstd.c
|
|
||||||
100644 cac9ee15f81a1607a03fbab3466cf89c588872c8 repo-pre-8/src/internal.h
|
|
||||||
100644 2257a2299b3bcf3ab15978d723843f26d0b4b346 repo-pre-8/src/xattr.c
|
|
||||||
```
|
|
||||||
|
|
||||||
These values define the immutable comparison baseline for Pre8. Concurrent
|
|
||||||
or later worktree changes are not assessed by this document.
|
|
||||||
|
|
||||||
## Execution Scope
|
|
||||||
|
|
||||||
Pre8 is limited to the following private responsibility-alignment tasks:
|
|
||||||
|
|
||||||
1. Move `z_erofs_load_lzma_config()` from the core decompressor file to the
|
|
||||||
LZMA backend without changing its name, signature, validation order,
|
|
||||||
state updates, or error behavior.
|
|
||||||
2. Move `z_erofs_load_deflate_config()` to the DEFLATE backend with its
|
|
||||||
existing format checks, window-bit limits, state updates, and errors
|
|
||||||
preserved.
|
|
||||||
3. Move `z_erofs_load_zstd_config()` to the ZSTD backend while preserving the
|
|
||||||
availability check, configuration checks, window-log limit, diagnostics,
|
|
||||||
and `WITH_ZSTDIO` behavior.
|
|
||||||
4. Replace the duplicated inline and shared xattr traversal paths with shared
|
|
||||||
private iterator helpers while preserving lookup priority, list order,
|
|
||||||
namespace and errno timing, validation differences, output accounting, and
|
|
||||||
buffer ownership.
|
|
||||||
|
|
||||||
The source allowlist is restricted to the six files identified above. This
|
|
||||||
baseline file is the only documentation path used by the baseline step.
|
|
||||||
|
|
||||||
Pre8 does not include superblock extraction, a new `compress.h` contract,
|
|
||||||
descriptor tables, decode callback ABI changes, codec primitive renaming,
|
|
||||||
typed errno conversion, Linux page or folio abstractions, broad function
|
|
||||||
reordering, or any item already recorded under `planning/reject/`.
|
|
||||||
|
|
||||||
## Initial Validation Status
|
|
||||||
|
|
||||||
This document records the execution baseline only. No implementation,
|
|
||||||
correctness, build, or runtime conclusion is made here.
|
|
||||||
|
|
||||||
| Validation item | Initial status |
|
|
||||||
|---|---|
|
|
||||||
| Pre8 source implementation | NOT RUN |
|
|
||||||
| Source allowlist and protected-path audit | NOT RUN |
|
|
||||||
| `git diff --check` | NOT RUN |
|
|
||||||
| Loader definition, declaration, reference, and body-equivalence checks | NOT RUN |
|
|
||||||
| Xattr iterator invariant and behavior review | NOT RUN |
|
|
||||||
| Direct-parent restoration checks for source commits | NOT RUN |
|
|
||||||
| Final-HEAD inverse-patch compatibility checks | NOT RUN |
|
|
||||||
| `WITH_ZSTDIO=0` build | NOT RUN |
|
|
||||||
| `WITH_ZSTDIO=1` build | NOT RUN |
|
|
||||||
| Basic plain/LZ4 QEMU mount, read, readdir, and unmount smoke | NOT RUN |
|
|
||||||
| Pre7 deferred QEMU coverage | NOT RUN |
|
|
||||||
| Pre8 xattr QEMU coverage | NOT RUN |
|
|
||||||
| Pre8 codec QEMU coverage | NOT RUN |
|
|
||||||
| QEMU cleanup and zero-residual-state checks | NOT RUN |
|
|
||||||
| Completion and evidence-honesty review | NOT RUN |
|
|
||||||
|
|
||||||
Historical evidence from an earlier snapshot is not a Pre8 result. Every
|
|
||||||
status above remains `NOT RUN` until supported by fresh evidence from the
|
|
||||||
final Pre8 DUT. This file must not be interpreted as a completion report.
|
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
# Pre8 Completion and Validation
|
|
||||||
|
|
||||||
## Final Verdict
|
|
||||||
|
|
||||||
Pre8 overall status is **FAIL**.
|
|
||||||
|
|
||||||
The required implementation, static review, revert review, build matrix, basic
|
|
||||||
plain/LZ4 smoke, and selected test suite were all executed. The selected suite
|
|
||||||
did not pass its required gate. In particular, TC004 produced a definite DUT
|
|
||||||
failure while twelve other DUT verdicts were blocked by test-harness defects or
|
|
||||||
prior test residue. Under the status definition in `planning/pre8`, a required
|
|
||||||
action that ran and failed a gate is `FAIL`, not `PASS` or `PARTIAL`.
|
|
||||||
|
|
||||||
This overall verdict does not erase the narrower successful results:
|
|
||||||
|
|
||||||
| Validation layer | Verdict | Scope |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Source implementation | PASS | Planned loader placement and xattr iterator work is present in the final source tree. |
|
|
||||||
| Static source review | PASS | Allowlist, token-equivalence, references, xattr invariants, and protected paths passed review. |
|
|
||||||
| Revert and history review | PASS | Accepted replacement commits passed their defined direct-parent and final-HEAD checks; historical failures remain disclosed. |
|
|
||||||
| Four build configurations | PASS | `default`, `debug`, `zstdio0`, and `zstdio1` built and passed module load/unload smoke. |
|
|
||||||
| Basic plain/LZ4 smoke | PASS | Independent run `20260812T210345.913633Z-770842-a2868dd9`. |
|
|
||||||
| Selected 19-case suite | FAIL | Automation: 5 PASS / 9 FAIL / 4 ERROR / 1 NOT_RUN. Audited DUT: 6 PASS / 1 FAIL / 12 BLOCKED. |
|
|
||||||
| Pre8 overall | **FAIL** | A required selected-suite gate ran and failed. |
|
|
||||||
|
|
||||||
No claim is made that Pre8, repo22, the LZMA issue, or the test harness was
|
|
||||||
fixed by this validation work.
|
|
||||||
|
|
||||||
## Final DUT Identity
|
|
||||||
|
|
||||||
The final repository identity used by both selected-suite and basic-smoke
|
|
||||||
evidence is:
|
|
||||||
|
|
||||||
```text
|
|
||||||
parent repository commit: d1f5b686e8945d06b6e8c0a0188b2262de0b4ac2
|
|
||||||
parent repository tree: 19f450085cad49d06f6fe05d180313f13d4347f0
|
|
||||||
repo-pre-8 tree: 497736695fcc4285760b24c5954c34d32b8af49f
|
|
||||||
repo-pre-8/src tree: cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2
|
|
||||||
```
|
|
||||||
|
|
||||||
Selected-suite DUT archive:
|
|
||||||
|
|
||||||
```text
|
|
||||||
bbcfd8a6a28faba3f7c5c7e827bde5578774be6e08b83d05485d58ee16a7fb6f
|
|
||||||
```
|
|
||||||
|
|
||||||
Basic-smoke DUT archive:
|
|
||||||
|
|
||||||
```text
|
|
||||||
402459ba6a6f55696d06474f7494a69ef1a5fe49063d565cacadece37e8b9ce1
|
|
||||||
```
|
|
||||||
|
|
||||||
The different archive hashes belong to different runners and archive
|
|
||||||
procedures. Both reports bind their run to the same final repository commit
|
|
||||||
and `repo-pre-8/src` tree.
|
|
||||||
|
|
||||||
## Source Delivery
|
|
||||||
|
|
||||||
### Accepted implementation
|
|
||||||
|
|
||||||
The final accepted source changes are:
|
|
||||||
|
|
||||||
1. `3d28d96fc48753231b1899fce6189e586cf988c6`
|
|
||||||
(`erofs: unify inline and shared xattr iteration`)
|
|
||||||
2. `aac1412056f9ae7269f7c0f85c0233ade8cc662a`
|
|
||||||
(`erofs: move codec config loaders atomically`)
|
|
||||||
|
|
||||||
The xattr commit introduces common private inline/shared iteration while
|
|
||||||
preserving the reviewed lookup order, list order, namespace and errno timing,
|
|
||||||
inline/shared validation differences, buffer ownership, and output accounting.
|
|
||||||
|
|
||||||
The atomic loader replacement moves the LZMA, DEFLATE, and ZSTD configuration
|
|
||||||
loaders to their backend files. The loader bodies remain token-equivalent to
|
|
||||||
the baseline, dispatch calls remain in the core, decode functions are not
|
|
||||||
changed, and no Linux page/folio or descriptor ABI was introduced.
|
|
||||||
|
|
||||||
### Superseded split-loader history
|
|
||||||
|
|
||||||
The following pushed commits remain in history and must not be described as
|
|
||||||
accepted independent delivery units:
|
|
||||||
|
|
||||||
| Commit | Historical final-HEAD inverse result | Final disposition |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `dd7f2483d468ec4397a863c7a871391ea1bc2c4c` | FAIL: conflict in `decompressor.c`; `internal.h` auto-merged as staged content | Superseded by `aac1412`; failure permanently retained. |
|
|
||||||
| `0dba0ea223bee8626b8cd3371562f87ed975a99f` | FAIL: conflict in `decompressor.c`; `internal.h` auto-merged as staged content | Superseded by `aac1412`; failure permanently retained. |
|
|
||||||
| `7c47f6d` | PASS | Superseded with the split-loader group by `aac1412`. |
|
|
||||||
|
|
||||||
All three split commits passed direct-parent restoration at the point where
|
|
||||||
they were introduced. That fact does not overwrite the two final-HEAD inverse
|
|
||||||
failures. The split group was reverted by `96f041f`, then replayed as the one
|
|
||||||
accepted atomic commit `aac1412`. Commit `3d28d96` was not superseded.
|
|
||||||
|
|
||||||
### Static and revert verdict
|
|
||||||
|
|
||||||
Final static and revert status is **PASS**:
|
|
||||||
|
|
||||||
- the implementation remained within the planned source allowlist;
|
|
||||||
- protected trees and unrelated paths were unchanged;
|
|
||||||
- all three moved loader bodies matched their baseline implementations;
|
|
||||||
- declaration, definition, and dispatch-call closure was correct;
|
|
||||||
- the ZSTD availability and `windowlog > 10` rejection order was preserved;
|
|
||||||
- codec decode bodies were unchanged;
|
|
||||||
- the xattr iterator behavior and ownership matrix passed independent review;
|
|
||||||
- `aac1412` restored its direct parent exactly when reverted;
|
|
||||||
- `aac1412` independently reverted from final HEAD without changing xattr;
|
|
||||||
- `3d28d96` independently reverted from final HEAD without changing the
|
|
||||||
accepted loader layout;
|
|
||||||
- final `repo-pre-8/src` matched the reviewed functional source tree;
|
|
||||||
- `git diff --check` and worktree cleanliness checks passed at static handoff.
|
|
||||||
|
|
||||||
The detailed history record is
|
|
||||||
`repo-pre-8/docs/pre8-loader-history-correction.md`.
|
|
||||||
|
|
||||||
## Build Validation
|
|
||||||
|
|
||||||
The selected-suite runner built four module configurations. Every
|
|
||||||
configuration passed build completion, SHA256 recording, unresolved-symbol
|
|
||||||
checks, and an actual `kldload`/`kldunload` smoke before case execution.
|
|
||||||
|
|
||||||
| Configuration | Verdict | SHA256 | Size |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `default` | PASS | `348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0` | 47,272 bytes |
|
|
||||||
| `debug` | PASS | `274189804511d249b34fbb3c223e9525b07c7c6266ec39d016ad2f33185001c7` | **UNKNOWN**; the harness did not persist size evidence before VM destruction |
|
|
||||||
| `zstdio0` | PASS | `348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0` | 47,272 bytes; byte-identical to `default` |
|
|
||||||
| `zstdio1` | PASS | `6cdb8e01fdac7805cb7ae12a9d1804b00d3e5cf37ef8b2f583137d36ee70426e` | 51,368 bytes |
|
|
||||||
|
|
||||||
The missing debug size is not reconstructed or inferred. No KLD or other
|
|
||||||
binary was committed.
|
|
||||||
|
|
||||||
## Basic Plain/LZ4 Smoke
|
|
||||||
|
|
||||||
Independent basic smoke run:
|
|
||||||
|
|
||||||
```text
|
|
||||||
run ID: 20260812T210345.913633Z-770842-a2868dd9
|
|
||||||
automation: PASS
|
|
||||||
runner exit: 0
|
|
||||||
DUT result: PASS for plain and LZ4 basic differential scope
|
|
||||||
guest: FreeBSD 15.0-RELEASE-p8 amd64
|
|
||||||
KLD SHA256: 527fe80ad7307d0200cfc4fec84c6fb86b914e89889e4a42ff0613fc24465015
|
|
||||||
KLD size: 47,272 bytes
|
|
||||||
```
|
|
||||||
|
|
||||||
All twelve runner stages passed. The run created a deterministic corpus with
|
|
||||||
256 regular files, 9 symlinks, and 43 directories. Both the plain and LZ4
|
|
||||||
images mounted read-only, passed a 307-entry differential preflight, completed
|
|
||||||
all four workers, and unmounted cleanly. The test QEMU exited gracefully, its
|
|
||||||
overlay and large temporary data were removed, and ports 10000 and 10001 were
|
|
||||||
released.
|
|
||||||
|
|
||||||
This result covers only plain/LZ4 basic mount, traversal, read, differential,
|
|
||||||
unmount, and cleanup behavior. It does not override the selected-suite
|
|
||||||
failures or blocked verdicts.
|
|
||||||
|
|
||||||
Evidence:
|
|
||||||
|
|
||||||
- `/work/tests-dev/erofsstress/demo-result/repo-pre-8-smoke-20260812/20260812T210345.913633Z-770842-a2868dd9/audit-report.md`
|
|
||||||
- `/work/tests-dev/erofsstress/demo-result/repo-pre-8-smoke-20260812/20260812T210345.913633Z-770842-a2868dd9/result.json`
|
|
||||||
- tests-dev commit `374b8e3ab4b0df24d6761802b70c694e2896d5fd`
|
|
||||||
|
|
||||||
## Selected Suite
|
|
||||||
|
|
||||||
Primary run:
|
|
||||||
|
|
||||||
```text
|
|
||||||
run ID: pre8-required-20260812T194817Z
|
|
||||||
cases: 19
|
|
||||||
automation: 5 PASS / 9 FAIL / 4 ERROR / 1 NOT_RUN
|
|
||||||
runner exit: 3
|
|
||||||
duration: 1892.44 seconds
|
|
||||||
audited DUT: 6 PASS / 1 FAIL / 12 BLOCKED
|
|
||||||
```
|
|
||||||
|
|
||||||
The automation status is the runner's result. The DUT status is a separate
|
|
||||||
evidence audit. An automation failure caused by a harness defect is not changed
|
|
||||||
to automation PASS. Likewise, a positive command observed before a missing
|
|
||||||
negative check does not make the full DUT case PASS.
|
|
||||||
|
|
||||||
### Per-case matrix
|
|
||||||
|
|
||||||
| Case | Automation | DUT | Audited observation |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| TC005 | FAIL | BLOCKED | Inline listing and both requested user xattr values succeeded. The missing-xattr `ENOATTR` assertion was never invoked because the truss output directory did not exist. |
|
|
||||||
| TC013 | PASS | PASS | Invalid NID returned `EINTEGRITY` (`ERR#97`) twice; mount, unmount, and zero-state checks passed. |
|
|
||||||
| TC079 | PASS | PASS | Packed user and trusted prefix values matched expected data and cleanup passed. |
|
|
||||||
| TC080 | FAIL | BLOCKED | Four packed-prefix values were correct. The missing-suffix `ENOATTR` assertion was not invoked because the truss output directory was absent. |
|
|
||||||
| TC082 | FAIL | BLOCKED | ACL bytes and ordering were observed, but automation compared spaced hex against an unspaced prefix; the user-namespace negative assertion also was not invoked. |
|
|
||||||
| TC067 | FAIL | PASS | Both shared files, the local xattr, and listing matched the fixture. Automation incorrectly expected one additional trailing `!`. |
|
|
||||||
| TC068 | FAIL | BLOCKED | Shared listing succeeded. The nonexistent lookup was not invoked because truss could not create its output file. |
|
|
||||||
| TC069 | PASS | PASS | Three shared xattrs were listed and all exact values were read; cleanup passed. |
|
|
||||||
| TC081 | PASS | PASS | Metabox shared, shared-prefix, and packed-prefix xattrs were listed and read from both files; cleanup passed. |
|
|
||||||
| TC117 | FAIL | BLOCKED | Both corrupt fixtures mounted and valid local shared data remained readable. Corrupt-entry errno assertions were not invoked because truss failed first. |
|
|
||||||
| TC135 | PASS | PASS | Metabox, packed, and primary-prefix fallback values matched expected data. |
|
|
||||||
| TC138 | FAIL | BLOCKED | Valid unordered and empty-header ACLs were read. Three malformed ACL assertions were not invoked because the scratch directory was absent. |
|
|
||||||
| TC140 | FAIL | BLOCKED | Positive compressed and fragment metabox carrier hashes and xattrs passed. Four negative mount commands were not invoked because truss failed opening its trace. |
|
|
||||||
| TC142 | FAIL | BLOCKED | Positive fragment-backed compressed metabox hash and xattrs passed. Four negative mount commands were not invoked for the same reason. |
|
|
||||||
| TC004 | ERROR | **FAIL** | LZMA image mounted, but SHA256 of the mounted 8 MiB `level.dat` timed out after 30 seconds. The process remained running and left the mount and `md0` busy. |
|
|
||||||
| TC084 | ERROR; follow-up FAIL | BLOCKED | Primary run was contaminated by TC004 residue. Fresh follow-up mounted LZ4 and found the target, but guest `dump.erofs` was absent before content verification. |
|
|
||||||
| TC102 | ERROR; follow-up FAIL | BLOCKED | Primary run was contaminated by TC004 residue. Fresh follow-up mounted DEFLATE, but missing guest `dump.erofs` prevented algorithm and content verification. |
|
|
||||||
| TC105 | ERROR; follow-up FAIL | BLOCKED | Primary run was contaminated by TC004 residue. Fresh follow-up mounted ZSTD with `zstdio1`, but missing guest `dump.erofs` prevented verification. |
|
|
||||||
| TC145 | NOT_RUN; follow-up ERROR | BLOCKED | Both zstdio modules built and initial load smoke passed. The follow-up queried and unloaded module name `erofs` instead of the loaded artifact name, so functional mount/read gates were not reached. |
|
|
||||||
|
|
||||||
### Definite DUT failure
|
|
||||||
|
|
||||||
TC004 is a definite observed DUT failure for this test run:
|
|
||||||
|
|
||||||
1. `lzma-level6.erofs` attached as `md0`.
|
|
||||||
2. The read-only EROFS mount succeeded.
|
|
||||||
3. The mounted `level.dat` existed.
|
|
||||||
4. SHA256 of the source file completed and returned
|
|
||||||
`ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461`.
|
|
||||||
5. SHA256 of the mounted 8 MiB file did not finish within 30 seconds.
|
|
||||||
6. The timed-out `sha256` process remained alive.
|
|
||||||
7. Unmount and `mdconfig -d` returned `Device busy`.
|
|
||||||
|
|
||||||
This evidence does **not** prove that Pre8 introduced the problem. No matching
|
|
||||||
Pre7 or pre-change comparison run with the same image, guest, module build,
|
|
||||||
and command is available. The issue is recorded separately in
|
|
||||||
`issues/pre8-lzma-read-timeout.md` without an attribution claim.
|
|
||||||
|
|
||||||
### Codec follow-up
|
|
||||||
|
|
||||||
Fresh follow-up run:
|
|
||||||
|
|
||||||
```text
|
|
||||||
run ID: pre8-codec-followup-20260812T202059Z
|
|
||||||
cases: TC084, TC102, TC105, TC145
|
|
||||||
automation: 3 FAIL / 1 ERROR
|
|
||||||
runner exit: 1
|
|
||||||
duration: 1136.92 seconds
|
|
||||||
audited DUT: 4 BLOCKED
|
|
||||||
```
|
|
||||||
|
|
||||||
The follow-up isolated these cases from TC004 residue, but it did not produce
|
|
||||||
codec functional PASS verdicts. TC084, TC102, and TC105 were blocked by absent
|
|
||||||
guest `dump.erofs`. TC145 was blocked by incorrect module-name lookup/unload
|
|
||||||
and cleanup behavior in the harness. These results remain FAIL/ERROR in
|
|
||||||
automation and BLOCKED for the DUT.
|
|
||||||
|
|
||||||
The harness findings are recorded in
|
|
||||||
`issues/pre8-test-harness-blockers.md`. No harness modification is part of
|
|
||||||
Pre8 source delivery.
|
|
||||||
|
|
||||||
Selected-suite evidence:
|
|
||||||
|
|
||||||
- `/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/summary.md`
|
|
||||||
- `/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/summary.json`
|
|
||||||
- `/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/pre8-required-20260812T194817Z/summary.json`
|
|
||||||
- `/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/pre8-required-20260812T194817Z/evidence/`
|
|
||||||
- `/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/pre8-codec-followup-20260812T202059Z/summary.json`
|
|
||||||
- `/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/pre8-codec-followup-20260812T202059Z/evidence/`
|
|
||||||
- tests-dev commit `46e6840f1b8918414af76c9a5731322c697eee8b`
|
|
||||||
|
|
||||||
## Fixtures and Immutable Inputs
|
|
||||||
|
|
||||||
The common base image was not modified:
|
|
||||||
|
|
||||||
```text
|
|
||||||
path: /work/tests-dev/lfs/freebsd-15-dev-src-20260811.bp
|
|
||||||
format: qcow2
|
|
||||||
mode: 0444
|
|
||||||
size: 16,515,530,752 bytes
|
|
||||||
SHA256: 67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef
|
|
||||||
```
|
|
||||||
|
|
||||||
Selected primary fixture deployment identities:
|
|
||||||
|
|
||||||
| Group | Manifest SHA256 | Checksum-list SHA256 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| G1 | `9ffe9e695a6544cb010a5d4ba1e0c2c09d7455e6d7e28cc81da54d2dd954f2f2` | `db416004ff6b00ad286e50da506168b35a544a7da5619042225198843e4c741c` |
|
|
||||||
| G4 | `6200842757dae30f3a5b0683d726d339a24e55dff98cd084597462289a9308aa` | `229c84c5436cf9b5b659ded375097fba13621c20a2cf2d845f146df737836622` |
|
|
||||||
| G5 | `c9540baafb53b3783233c3950f4d8548c28585cd32335dadc14db613692a8978` | `d08138b1bd51579cbf5461a73abce9d7fddc9cdb8ace1329c9f1581d41e1095f` |
|
|
||||||
|
|
||||||
Follow-up G5 deployment identities:
|
|
||||||
|
|
||||||
```text
|
|
||||||
manifest: 9be85e48115f2dd2cae058f2a4ea7438512f28e647c30476d049d6b8025b02fd
|
|
||||||
checksum list: 7513425c98400f641523083bf0d06b2d548aa3163dfcdfe980dca2b0e1900acd
|
|
||||||
```
|
|
||||||
|
|
||||||
Deployment hashes can include run-specific metadata. Image, source, generator,
|
|
||||||
and checksum evidence remains beneath each run's `fixture-evidence/` and
|
|
||||||
per-case evidence directories.
|
|
||||||
|
|
||||||
## Cleanup and Guard Integrity
|
|
||||||
|
|
||||||
- The selected primary and follow-up QEMUs were force-destroyed by the runner
|
|
||||||
after their final errors.
|
|
||||||
- Their run-owned overlays were deleted.
|
|
||||||
- Ports 10000 and 10001 were released and closed.
|
|
||||||
- The independent basic-smoke QEMU shut down gracefully and its overlay was
|
|
||||||
removed.
|
|
||||||
- Guard PID 26318 retained its identity and TCP port 9222 remained active.
|
|
||||||
- Base-image SHA256, mode, and size were unchanged before and after the runs.
|
|
||||||
- The DUT commit and source tree remained unchanged and clean.
|
|
||||||
- No DUT source, repo22 source, base image, test source, fixture generator, or
|
|
||||||
`oldtests` content was modified during validation.
|
|
||||||
|
|
||||||
Cleanup of the disposable VM does not change TC004's case-level cleanup result:
|
|
||||||
the case itself failed to terminate its read process and could not unmount or
|
|
||||||
detach `md0`. VM destruction only removed the run environment afterward.
|
|
||||||
|
|
||||||
## Final Handoff
|
|
||||||
|
|
||||||
Pre8 delivers the planned source-responsibility changes and passes static,
|
|
||||||
revert, build, and basic plain/LZ4 smoke validation. It does not satisfy the
|
|
||||||
full required validation gate because the selected suite contains one definite
|
|
||||||
DUT failure and twelve blocked DUT cases. The honest final status is therefore
|
|
||||||
**FAIL**.
|
|
||||||
|
|
||||||
Open follow-up records:
|
|
||||||
|
|
||||||
- `issues/pre8-lzma-read-timeout.md`
|
|
||||||
- `issues/pre8-test-harness-blockers.md`
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
# Pre8 Loader History Correction
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This record corrects the commit organization of the Pre8 codec configuration
|
|
||||||
loader moves. It does not report a source behavior defect and does not rewrite,
|
|
||||||
amend, squash, or hide any pushed commit.
|
|
||||||
|
|
||||||
The affected historical commits are:
|
|
||||||
|
|
||||||
```text
|
|
||||||
dd7f2483d468ec4397a863c7a871391ea1bc2c4c LZMA loader move
|
|
||||||
0dba0ea223bee8626b8cd3371562f87ed975a99f DEFLATE loader move
|
|
||||||
7c47f6d ZSTD loader move
|
|
||||||
3d28d96fc48753231b1899fce6189e586cf988c6 xattr iterator change
|
|
||||||
```
|
|
||||||
|
|
||||||
## Recorded Results
|
|
||||||
|
|
||||||
Each of the three loader commits restores its direct parent's complete tree
|
|
||||||
when reverted at the commit where it was introduced. Those direct-parent
|
|
||||||
revert checks are `PASS`.
|
|
||||||
|
|
||||||
When each commit is reverted independently from final functional commit
|
|
||||||
`3d28d96`, the results are:
|
|
||||||
|
|
||||||
| Commit | Final-HEAD independent revert | Result |
|
|
||||||
|---|---|---|
|
|
||||||
| `dd7f248` | Unmerged conflict in `decompressor.c`; `internal.h` auto-merged as a staged modification | FAIL |
|
|
||||||
| `0dba0ea` | Unmerged conflict in `decompressor.c`; `internal.h` auto-merged as a staged modification | FAIL |
|
|
||||||
| `7c47f6d` | Applies without conflict | PASS |
|
|
||||||
| `3d28d96` | Applies without conflict | PASS |
|
|
||||||
|
|
||||||
The two failures are caused by overlapping patch context in `decompressor.c`.
|
|
||||||
In both cases, `internal.h` is automatically merged as a staged modification,
|
|
||||||
not left as an unmerged conflict. This is a commit organization problem, not
|
|
||||||
evidence of a codec implementation or xattr behavior problem.
|
|
||||||
|
|
||||||
The `dd7f248` and `0dba0ea` final-HEAD results remain permanently recorded as
|
|
||||||
`FAIL`. The `7c47f6d` result remains `PASS`, but that commit is superseded with
|
|
||||||
the other two loader commits so the loader responsibility change has one
|
|
||||||
atomic acceptance unit.
|
|
||||||
|
|
||||||
## Correction Strategy
|
|
||||||
|
|
||||||
The three split loader commits will be reverted in reverse order without
|
|
||||||
rewriting history. Their exact combined five-path change will then be replayed
|
|
||||||
as one atomic replacement commit. The replacement is limited to:
|
|
||||||
|
|
||||||
```text
|
|
||||||
repo-pre-8/src/decompressor.c
|
|
||||||
repo-pre-8/src/decompressor_lzma.c
|
|
||||||
repo-pre-8/src/decompressor_deflate.c
|
|
||||||
repo-pre-8/src/decompressor_zstd.c
|
|
||||||
repo-pre-8/src/internal.h
|
|
||||||
```
|
|
||||||
|
|
||||||
Commit `3d28d96` remains accepted and is not superseded. Its `xattr.c` content
|
|
||||||
must remain unchanged through the correction.
|
|
||||||
|
|
||||||
The new acceptance objects are:
|
|
||||||
|
|
||||||
1. the atomic replacement loader commit, which must restore its direct parent
|
|
||||||
exactly when reverted and must independently revert from final `HEAD`
|
|
||||||
without affecting xattr content; and
|
|
||||||
2. existing xattr commit `3d28d96`, which must independently revert from final
|
|
||||||
`HEAD` without affecting the final loader layout.
|
|
||||||
|
|
||||||
## Validation Status
|
|
||||||
|
|
||||||
This document records static Git evidence only. No build or QEMU test has been
|
|
||||||
run for this history correction. Build and runtime validation remain
|
|
||||||
`NOT RUN` until later Pre8 validation produces fresh evidence from the final
|
|
||||||
DUT.
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
# Pre9 LZMA Diagnostic Implementation Baseline
|
|
||||||
|
|
||||||
## Baseline Meaning
|
|
||||||
|
|
||||||
The Pre9 planning phase ended when the planning documents were committed at
|
|
||||||
`d1ee2e05b82b5e8a8927861f1e981710532f2f23`. This file starts the
|
|
||||||
implementation phase and records identities only. It does not claim that the
|
|
||||||
TC004 root cause is known, that Pre8 introduced the observed timeout, or that
|
|
||||||
any source or test-harness fix has been selected or implemented.
|
|
||||||
|
|
||||||
All values below were read from Git objects or the named evidence files on
|
|
||||||
2026-08-13 UTC. Historical Pre8 evidence is context for controlled Pre9
|
|
||||||
diagnosis, not a Pre9 test result.
|
|
||||||
|
|
||||||
## Main Repository Identity
|
|
||||||
|
|
||||||
Repository: `/work/erofs-freebsd-pre`
|
|
||||||
|
|
||||||
```text
|
|
||||||
branch: main
|
|
||||||
execution-start commit: d1ee2e05b82b5e8a8927861f1e981710532f2f23
|
|
||||||
execution-start tree: 95a55ff912d007ca40bd578057e8a4cc6a21bbd9
|
|
||||||
xdm/main: d1ee2e05b82b5e8a8927861f1e981710532f2f23
|
|
||||||
remote xdm main: d1ee2e05b82b5e8a8927861f1e981710532f2f23
|
|
||||||
initial dirty entries: 0
|
|
||||||
```
|
|
||||||
|
|
||||||
Snapshot identities at the execution-start commit:
|
|
||||||
|
|
||||||
```text
|
|
||||||
snapshot subtree src tree
|
|
||||||
repo-pre-7 b8f9af2cd55225c4348b79ff5910ae6fc83cd517 dc203534d7b5721905f8538026e4c59346106020
|
|
||||||
repo-pre-8 1e24c992a5b071e6fdabfdc42d342b6ed5a91cf5 cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2
|
|
||||||
repo-pre-9 1e24c992a5b071e6fdabfdc42d342b6ed5a91cf5 cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2
|
|
||||||
```
|
|
||||||
|
|
||||||
The equal Pre8 and Pre9 object identities establish that Pre9 starts as an
|
|
||||||
exact tracked snapshot of Pre8. Pre7 is intentionally different and remains
|
|
||||||
the earlier controlled comparison point.
|
|
||||||
|
|
||||||
## Conditional Source Allowlist Identity
|
|
||||||
|
|
||||||
The primary conditional allowlist is `zdata.c`, `decompressor_lzma.c`, and
|
|
||||||
`internal.h`. The remaining three files require the additional decision gates
|
|
||||||
defined by the plan. Their baseline modes and blobs are:
|
|
||||||
|
|
||||||
```text
|
|
||||||
gate mode blob path
|
|
||||||
primary 100644 54c1c88e5c368e7b5f6a16188c48406767850821 repo-pre-9/src/zdata.c
|
|
||||||
primary 100644 688acd704e28daa46369fa2e63e895bce5262774 repo-pre-9/src/decompressor_lzma.c
|
|
||||||
primary 100644 9821fe3a8b5fcaaeb3939d191f15e9ce637cc8d1 repo-pre-9/src/internal.h
|
|
||||||
extra 100644 ca5d33cd42145159d71e153f115128ac75258708 repo-pre-9/src/inode.c
|
|
||||||
extra 100644 b233f138d036a2b37394946b382034955dc2a1df repo-pre-9/src/erofs_vnops.c
|
|
||||||
extra 100644 51170741a0fb5eced814db898c1a233e8a23088a repo-pre-9/src/zmap.c
|
|
||||||
```
|
|
||||||
|
|
||||||
This identity table authorizes no source change by itself. Source edits remain
|
|
||||||
conditional on controlled evidence and the applicable decision gate.
|
|
||||||
|
|
||||||
## tests-dev and Base Image Identity
|
|
||||||
|
|
||||||
The external test repository was inspected without modification:
|
|
||||||
|
|
||||||
```text
|
|
||||||
repository: /work/tests-dev
|
|
||||||
branch: main
|
|
||||||
current commit: 374b8e3ab4b0df24d6761802b70c694e2896d5fd
|
|
||||||
current tree: c438e72ebe94a6f10801999bfbdd36b43134d471
|
|
||||||
xdm/main: 374b8e3ab4b0df24d6761802b70c694e2896d5fd
|
|
||||||
initial dirty entries: 27 untracked paths
|
|
||||||
dirty inventory SHA256: bca9ca20e85698d04dad820a11bd0bbb117492c967d6fd338e7acf61bb8fa957
|
|
||||||
```
|
|
||||||
|
|
||||||
The pre-existing tests-dev dirty inventory was:
|
|
||||||
|
|
||||||
```text
|
|
||||||
demo-result/FINAL-REPORT.md
|
|
||||||
demo-result/audit-checklist.md
|
|
||||||
demo-result/audit-findings.md
|
|
||||||
demo-result/current-status.md
|
|
||||||
demo-result/fix-plan.md
|
|
||||||
demo-result/fix-verification-report.json
|
|
||||||
demo-result/progress-report.md
|
|
||||||
demo-result/repo-pre-6-smoke-20260812/
|
|
||||||
demo-result/repo22-full-20260811T065312Z/
|
|
||||||
demo-result/repo22-full-20260811T071634Z/
|
|
||||||
demo-result/repo22-full-20260811T073716Z/
|
|
||||||
demo-result/repo22-full-20260811T082907Z/
|
|
||||||
demo-result/repo22-full-20260811T095621Z/
|
|
||||||
demo-result/test-execution-summary.md
|
|
||||||
erofsstress/demo-result/repo-pre-3-smoke-20260812/
|
|
||||||
erofsstress/demo-result/repo-pre-6-smoke-20260812/
|
|
||||||
guest/setup-build-env.sh
|
|
||||||
lfs/FreeBSD-15.0-RELEASE-src.txz
|
|
||||||
scripts/check-kernel-src.sh
|
|
||||||
scripts/complete-setup-and-test.py
|
|
||||||
scripts/install-kernel-sources.py
|
|
||||||
scripts/manual-fix.sh
|
|
||||||
scripts/quick-install-src.py
|
|
||||||
scripts/run-final-test.sh
|
|
||||||
scripts/setup-build-env-simple.py
|
|
||||||
scripts/setup-build-env.py
|
|
||||||
scripts/simple-install-kernel-src.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
These paths are not owned by this baseline step and must not be staged,
|
|
||||||
modified, or removed as part of it.
|
|
||||||
|
|
||||||
Immutable base image identity:
|
|
||||||
|
|
||||||
```text
|
|
||||||
path: /work/tests-dev/lfs/freebsd-15-dev-src-20260811.bp
|
|
||||||
format: QEMU QCOW2 Image (v3)
|
|
||||||
mode: 0444
|
|
||||||
size: 16,515,530,752 bytes
|
|
||||||
SHA256: 67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef
|
|
||||||
```
|
|
||||||
|
|
||||||
The base image is an input only. It must not be modified during Pre9 testing.
|
|
||||||
|
|
||||||
## Historical TC004 Evidence Identity
|
|
||||||
|
|
||||||
The prior observation is preserved by tests-dev evidence commit
|
|
||||||
`46e6840f1b8918414af76c9a5731322c697eee8b`, tree
|
|
||||||
`7178de49f3f429796d6de71a910d71bfccd5745a`, with subject
|
|
||||||
`evidence: record repo-pre-8 required smoke`.
|
|
||||||
|
|
||||||
```text
|
|
||||||
run ID: pre8-required-20260812T194817Z
|
|
||||||
case: TC004 - LZMA Compressed File Read
|
|
||||||
historical DUT commit: d1f5b686e8945d06b6e8c0a0188b2262de0b4ac2
|
|
||||||
historical DUT src tree: cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2
|
|
||||||
DUT archive SHA256: bbcfd8a6a28faba3f7c5c7e827bde5578774be6e08b83d05485d58ee16a7fb6f
|
|
||||||
module SHA256: 348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0
|
|
||||||
fixture image: G5/images/lzma-level6.erofs
|
|
||||||
fixture image SHA256: 32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9
|
|
||||||
source file: G5/sources/levels/level.dat
|
|
||||||
source file SHA256: ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461
|
|
||||||
deployment manifest: c9540baafb53b3783233c3950f4d8548c28585cd32335dadc14db613692a8978
|
|
||||||
fixture checksum hash: d08138b1bd51579cbf5461a73abce9d7fddc9cdb8ace1329c9f1581d41e1095f
|
|
||||||
TC004 evidence SHA256: de6982a11fa368fbaad7d837586daa899789cd4cd8b9f698974a3ef4e251811f
|
|
||||||
```
|
|
||||||
|
|
||||||
Evidence paths:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/pre8-required-20260812T194817Z/summary.json
|
|
||||||
/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/pre8-required-20260812T194817Z/evidence/TC004/TC004_evidence.json
|
|
||||||
/work/tests-dev/demo-result/repo-pre-8-smoke-20260812/summary.md
|
|
||||||
/work/erofs-freebsd-pre/issues/pre8-lzma-read-timeout.md
|
|
||||||
```
|
|
||||||
|
|
||||||
The historical automation verdict was `ERROR` and the audited DUT verdict was
|
|
||||||
`FAIL`: mount and lookup succeeded, but hashing the mounted 8 MiB `level.dat`
|
|
||||||
did not finish within 30 seconds. PID 95693 remained active, and the mount and
|
|
||||||
`md0` stayed busy until the disposable VM was destroyed. Attribution remains
|
|
||||||
`UNKNOWN`. These facts neither prove a Pre8 regression nor select a Pre9 fix.
|
|
||||||
|
|
||||||
## Initial Implementation Status
|
|
||||||
|
|
||||||
| Item | Status |
|
|
||||||
|---|---|
|
|
||||||
| Pre9 planning | COMPLETE |
|
|
||||||
| Pre9 implementation baseline | RECORDED |
|
|
||||||
| tests-dev TC004 prerequisite corrections | NOT RUN |
|
|
||||||
| tests-dev remaining full-suite prerequisites | NOT RUN |
|
|
||||||
| Controlled Pre7 reproduction | NOT RUN |
|
|
||||||
| Controlled Pre8 reproduction | NOT RUN |
|
|
||||||
| Controlled unchanged Pre9 reproduction | NOT RUN |
|
|
||||||
| Manual SSH diagnosis | NOT RUN |
|
|
||||||
| Hypothesis decision gates | NOT RUN |
|
|
||||||
| Source decision | NOT RUN |
|
|
||||||
| Optional diagnostic instrumentation | NOT RUN |
|
|
||||||
| Pre9 source implementation | NOT RUN |
|
|
||||||
| Source static review | NOT RUN |
|
|
||||||
| Source direct-parent revert gate | NOT RUN |
|
|
||||||
| Source final-HEAD inverse gate | NOT RUN |
|
|
||||||
| `WITH_ZSTDIO=0` build | NOT RUN |
|
|
||||||
| `WITH_ZSTDIO=1` build | NOT RUN |
|
|
||||||
| TC004 | NOT RUN |
|
|
||||||
| Extended LZMA matrix | NOT RUN |
|
|
||||||
| Plain/LZ4 smoke | NOT RUN |
|
|
||||||
| Full regression | NOT RUN |
|
|
||||||
| QEMU cleanup and zero-residual-state checks | NOT RUN |
|
|
||||||
| Pre9 completion and evidence-honesty review | NOT RUN |
|
|
||||||
| Pre9 overall | NOT RUN |
|
|
||||||
|
|
||||||
No diagnostic command, tests-dev prerequisite, controlled comparison, source
|
|
||||||
change, build, QEMU run, or manual SSH investigation has been performed for
|
|
||||||
Pre9 at this baseline. Fresh evidence is required before any status above can
|
|
||||||
advance or any root-cause or repair claim can be made.
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
# Pre9 decoded extent cache final manual validation
|
|
||||||
|
|
||||||
Date: 2026-08-13
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This run validated the mount-scoped decoded LZMA extent cache at enclosing
|
|
||||||
repository commit `cdcf276d12169a672d2de42996532a470ac061d9`.
|
|
||||||
|
|
||||||
Controlled identities:
|
|
||||||
|
|
||||||
- `repo-pre-9` tree: `9d7eaf63a1c5d07320af3ef39930fc0a3530dd11`
|
|
||||||
- `repo-pre-9/src` tree: `e657e8a63b097b061670f75ca01947a568ef33d5`
|
|
||||||
- guest-built KLD SHA-256:
|
|
||||||
`473a6205f43905972f2417609d43f67ab2cb51ea79bc1716fffa5c1914ff85af`
|
|
||||||
- LZMA image SHA-256:
|
|
||||||
`32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9`
|
|
||||||
- LZMA source SHA-256:
|
|
||||||
`ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461`
|
|
||||||
|
|
||||||
The existing fresh QEMU process on host port 10030 was reused. No second VM
|
|
||||||
was created. The guest used FreeBSD 15.0-RELEASE-p8 under QEMU TCG with 6 GiB
|
|
||||||
RAM and four virtual CPUs. The KLD was built in the guest with
|
|
||||||
`make WITH_ZSTDIO=0`.
|
|
||||||
|
|
||||||
The VM used the existing base image
|
|
||||||
`/work/tests-dev/lfs/freebsd-15-dev-src-20260811.bp`. Its previously audited
|
|
||||||
SHA-256 is
|
|
||||||
`67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef`.
|
|
||||||
This run relied on that established integrity record and did not repeat the
|
|
||||||
approximately 16 GiB image hash, so base-image hashing did not block the final
|
|
||||||
validation.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
| Area | Verdict | Result |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Guest build, KLD load and fixture mounts | PASS | Build returned zero, `kldload` returned zero and both LZMA and LZ4 images mounted read-only. |
|
|
||||||
| LZMA single-read correctness | PASS | 4 KiB, 16 KiB, 64 KiB and 1 MiB single `pread()` calls returned the requested bytes with `errno=0`; every output range matched the source range SHA-256. |
|
|
||||||
| LZMA full-file correctness | PASS | Cold and warm full SHA-256 runs returned zero and matched the 8 MiB source hash. |
|
|
||||||
| LZMA liveness and performance | PASS | Cold full SHA completed in 2.16 seconds and warm full SHA in 1.44 seconds, both below the 120-second host hard limit. |
|
|
||||||
| LZMA concurrency | PASS | Two simultaneous full SHA processes both returned zero and the expected hash; guest real times were 22.52 and 21.97 seconds. |
|
|
||||||
| Non-LZMA regression | PASS | The 8 MiB LZ4 fixture returned the expected SHA-256 in 9.03 seconds. |
|
|
||||||
| Cleanup and guard integrity | PASS | Test QEMU PID 812999 exited, port 10030 closed, its overlay was deleted, and guard PID 26318/port 9222 remained alive and reachable. |
|
|
||||||
|
|
||||||
Overall verdict: **PASS for the required final manual smoke scope**.
|
|
||||||
|
|
||||||
## Single `pread()` evidence
|
|
||||||
|
|
||||||
Each probe program performs one target-file `pread()`. Truss confirmed one
|
|
||||||
target call at offset zero for every requested length. Dynamic-loader reads are
|
|
||||||
not counted.
|
|
||||||
|
|
||||||
| Length | Returned | Probe command wall time | Output/source range hash | Verdict |
|
|
||||||
| ---: | ---: | ---: | --- | --- |
|
|
||||||
| 4 KiB | 4 KiB | 2.696 s | `1c3c59331a4849514667bbc51c078327577b98f75a62996bbc2fe310b014dd79` | PASS |
|
|
||||||
| 16 KiB | 16 KiB | 2.140 s | `2433ce7c2ea151f487a319447ce4fe14e1a2c2af9f0e5113fe47fc74b6138eee` | PASS |
|
|
||||||
| 64 KiB | 64 KiB | 1.369 s | `2bb87afd3b9fab420cbe55b782d69a7342150e8816a35efacf22d2ab3012815d` | PASS |
|
|
||||||
| 1 MiB | 1 MiB | 3.838 s | `52e806509e5dfeb523904f167fca765d001ea749351ecf51738e61a5352a1ba3` | PASS |
|
|
||||||
|
|
||||||
These wall times include SSH and truss overhead and are not pure kernel read
|
|
||||||
times.
|
|
||||||
|
|
||||||
## Full-file SHA evidence
|
|
||||||
|
|
||||||
The 8 MiB LZMA source hash is:
|
|
||||||
|
|
||||||
`ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461`
|
|
||||||
|
|
||||||
| Run | Exit | Guest real time | Captured hash | Verdict |
|
|
||||||
| --- | ---: | ---: | --- | --- |
|
|
||||||
| Cold, fresh mount | 0 | 2.16 s | expected hash | PASS |
|
|
||||||
| Warm, same mount | 0 | 1.44 s | expected hash | PASS |
|
|
||||||
| Concurrent process 1 | 0 | 22.52 s | expected hash | PASS |
|
|
||||||
| Concurrent process 2 | 0 | 21.97 s | expected hash | PASS |
|
|
||||||
|
|
||||||
The concurrency result shows substantial contention compared with a single
|
|
||||||
reader, but it completed correctly and stayed well inside the 120-second hard
|
|
||||||
limit. This run does not claim concurrency performance is optimized.
|
|
||||||
|
|
||||||
## Baseline comparison
|
|
||||||
|
|
||||||
The preceding controlled Pre7/Pre8/Pre9 run sampled each full SHA after about
|
|
||||||
eight seconds. Each process was still inside the LZMA decompression path and
|
|
||||||
had advanced only about 1.0-1.25 MiB; no final hash was captured. That report
|
|
||||||
therefore classified full-read liveness as failed and correctness as blocked.
|
|
||||||
|
|
||||||
With the mount-scoped decoded extent cache, the same 8 MiB fixture completed
|
|
||||||
with the correct hash in 2.16 seconds cold and 1.44 seconds warm. This closes
|
|
||||||
the previous full-file correctness block for this fixture and demonstrates a
|
|
||||||
material liveness improvement. It does not establish a precise speedup ratio,
|
|
||||||
because the baseline process was terminated at the observation point rather
|
|
||||||
than allowed to finish.
|
|
||||||
|
|
||||||
## Non-LZMA result
|
|
||||||
|
|
||||||
The LZ4 compact-64k image contained `compressed.bin` with expected SHA-256:
|
|
||||||
|
|
||||||
`3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880`
|
|
||||||
|
|
||||||
The mounted file produced the same hash, returned zero and completed in 9.03
|
|
||||||
seconds of guest real time.
|
|
||||||
|
|
||||||
## Kernel and cleanup observations
|
|
||||||
|
|
||||||
No EROFS panic, assertion, mount error or decompression error was found in the
|
|
||||||
captured dmesg tail. The image emitted pre-existing root-filesystem directory
|
|
||||||
warnings during boot; they occurred before the test KLD was loaded and are not
|
|
||||||
attributed to EROFS.
|
|
||||||
|
|
||||||
All test-specific mounts and md providers were explicitly detached before VM
|
|
||||||
shutdown. A final generic cleanup command contained an awk quoting error, but
|
|
||||||
it ran only after the explicit LZMA and LZ4 unmount/md detach operations had
|
|
||||||
already returned zero. Host-side cleanup independently confirmed:
|
|
||||||
|
|
||||||
- PID 812999 absent;
|
|
||||||
- port 10030 closed;
|
|
||||||
- test overlay absent;
|
|
||||||
- guard PID 26318 alive;
|
|
||||||
- guard port 9222 open.
|
|
||||||
|
|
||||||
## Uncovered cases
|
|
||||||
|
|
||||||
This is a targeted final smoke validation, not a full feature suite. It did not
|
|
||||||
exercise partial-reference LZMA, metadata tailpacking, fragments, multi-device
|
|
||||||
images, forced unmount under active I/O, repeated mount/unmount under memory
|
|
||||||
pressure, or deliberate allocation failure. Those remain separate regression
|
|
||||||
and stress-test work.
|
|
||||||
|
|
||||||
Concise machine-readable evidence is stored in
|
|
||||||
`docs/pre9-manual-evidence/pre9-cache-final-result.json`. Target syscall lines
|
|
||||||
are stored in `docs/pre9-manual-evidence/pre9-cache-final-probes.txt`.
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
# Pre9 controlled manual QEMU evidence audit
|
|
||||||
|
|
||||||
Date: 2026-08-13
|
|
||||||
|
|
||||||
## Scope and evidence status
|
|
||||||
|
|
||||||
This report audits the already completed manual run at
|
|
||||||
`/work/tests-dev/temp/pre9-manual-20260813-run3/`. No QEMU test was rerun.
|
|
||||||
The long-lived guard VM (PID 26318, host port 9222) was not touched.
|
|
||||||
|
|
||||||
The automated TC004 implementation remains `PENDING_FIX/BLOCKED` in
|
|
||||||
`/work/tests-dev/fix-todo/tc004-automation.md`. Run3 is a manual substitute;
|
|
||||||
it is not evidence that TC004 automation passes.
|
|
||||||
|
|
||||||
Run history:
|
|
||||||
|
|
||||||
- Run1: infrastructure failure; no retained result directory is available.
|
|
||||||
- Run2: `INFRA`. Guest SSH authentication failed for Pre7 and Pre8, then the
|
|
||||||
host runner was interrupted while preparing Pre9. It produced no DUT result.
|
|
||||||
- Run3: valid manual run. All three DUTs built, loaded, mounted, executed the
|
|
||||||
bounded probes, produced a live SHA stack sample, and cleaned up.
|
|
||||||
|
|
||||||
## Verdict
|
|
||||||
|
|
||||||
| Question | Verdict | Evidence |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 4 KiB, 16 KiB, 64 KiB and 1 MiB single-syscall read correctness | PASS | Every version returned the requested byte count, `errno=0`, matched the source-range SHA-256, exited zero, and has exactly one target-file `pread()` in truss. |
|
|
||||||
| First 1 MiB sequential `dd` read | PASS | Every version returned zero and copied 1 MiB within the 20-second bound. This is a bounded smoke check, not proof of one 1 MiB kernel read. |
|
|
||||||
| Full-file SHA correctness | BLOCKED | No version retained a hash or an exit status for the background SHA. `sha_after` is empty and process disappearance is not correctness evidence. |
|
|
||||||
| Full-file read liveness/performance | FAIL | After an eight-second observation delay, SHA was still running in the LZMA decode path and had advanced only about 1.0-1.25 MiB. This is unacceptable for the 8 MiB smoke fixture and reproduces across all three versions. |
|
|
||||||
| Pre7 to Pre8/Pre9 regression attribution | PASS: no Pre9 regression demonstrated | Pre8 and Pre9 have the same `src` tree and identical KLD hash. Pre7 has a different source tree/KLD but shows the same symptom and stack. The evidence attributes the issue to shared behavior, not a Pre9-only change. |
|
|
||||||
|
|
||||||
Overall verdict: **PARTIAL**. Bounded reads are correct, but the full-file
|
|
||||||
correctness verdict is blocked and full-file liveness fails.
|
|
||||||
|
|
||||||
## Runner semantics audit
|
|
||||||
|
|
||||||
The runner creates a fresh qcow2 overlay per version over the read-only base,
|
|
||||||
archives the selected repository subtree, builds the KLD in the guest, mounts
|
|
||||||
the same LZMA fixture, and runs four probes. Each probe invokes a C program that
|
|
||||||
contains one target-file `pread()` and writes the returned bytes to a file.
|
|
||||||
The runner then hashes that file and compares it with bytes read from the
|
|
||||||
uncompressed source fixture.
|
|
||||||
|
|
||||||
Important field meanings:
|
|
||||||
|
|
||||||
- `commit`: Git tree object for the version directory at the enclosing repo
|
|
||||||
HEAD. It is not a standalone commit ID.
|
|
||||||
- `src_tree`: Git tree object for that version's `src` directory.
|
|
||||||
- `probes[].elapsed`: host wall time for the complete SSH command, including
|
|
||||||
SSH and truss overhead. It is not pure kernel decompression time.
|
|
||||||
- `metadata.hash_match`: equality between the mounted output-range hash and
|
|
||||||
the uncompressed source-range hash.
|
|
||||||
- `signal=0`: runner shorthand for probe return code zero. It is not a signal
|
|
||||||
collected through `waitpid()`.
|
|
||||||
- `dd_1m`: a userspace `dd bs=1m count=1` result. It does not establish the
|
|
||||||
size or count of VOP/kernel reads.
|
|
||||||
- `sha_pid`: PID printed after starting a background `sha256` command.
|
|
||||||
- `diagnostic_sample`: process table, kernel stack, descriptor offset, mount,
|
|
||||||
md device and dmesg captured after an unconditional eight-second sleep.
|
|
||||||
- `sha_after`: process status followed by `sha.out` and `sha.err`. Empty output
|
|
||||||
means neither a process row nor captured SHA/error output was available.
|
|
||||||
- `status=PARTIAL`: runner-generated fallback when any bounded probe succeeds.
|
|
||||||
It does not mean full SHA correctness passed.
|
|
||||||
|
|
||||||
The full SHA was not run under `timeout`. The runner waited eight seconds,
|
|
||||||
sampled it, sent TERM, slept two seconds, then attempted KILL, and finally read
|
|
||||||
the output files. No start/end timestamp or exit status was recorded. Therefore
|
|
||||||
the exact SHA lifetime is unknown; the only defensible timing statement is that
|
|
||||||
it was still active approximately eight seconds after launch.
|
|
||||||
|
|
||||||
`sha_after` contains only `,state=,command=` for all versions. The subsequent
|
|
||||||
KILL reports `No such process`. This establishes only that the sampled PID no
|
|
||||||
longer existed after TERM plus the two-second delay. It does not distinguish a
|
|
||||||
successful completion from TERM handling, and the absent `sha.out` means no
|
|
||||||
hash can be validated. Process disappearance must not be reported as PASS.
|
|
||||||
|
|
||||||
## Controlled identities and setup
|
|
||||||
|
|
||||||
The common fixture hashes were:
|
|
||||||
|
|
||||||
- Image: `32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9`
|
|
||||||
- Source: `ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461`
|
|
||||||
|
|
||||||
| Version | Repository tree | `src` tree | KLD SHA-256 | Build/load/mount |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| Pre7 | `b8f9af2cd55225c4348b79ff5910ae6fc83cd517` | `dc203534d7b5721905f8538026e4c59346106020` | `33a52f2f16a94afda0501d305b238678b96c71e420d4b8bbcbeec6ffcdf1aae5` | PASS/PASS/PASS |
|
|
||||||
| Pre8 | `1e24c992a5b071e6fdabfdc42d342b6ed5a91cf5` | `cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2` | `348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0` | PASS/PASS/PASS |
|
|
||||||
| Pre9 | `dc0c01157b5c925684bd77c57ed6703904af7453` | `cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2` | `348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0` | PASS/PASS/PASS |
|
|
||||||
|
|
||||||
Pre8 and Pre9 are runtime-identical for this test according to both the source
|
|
||||||
tree and the produced KLD hash.
|
|
||||||
|
|
||||||
## Single-syscall probes
|
|
||||||
|
|
||||||
All probes used offset zero. Times below include SSH/truss overhead.
|
|
||||||
|
|
||||||
| Version | Length | Returned | Hash match | Elapsed | Exactly one target `pread()` |
|
|
||||||
| --- | ---: | ---: | --- | ---: | --- |
|
|
||||||
| Pre7 | 4 KiB | 4 KiB | yes | 1.299 s | yes |
|
|
||||||
| Pre7 | 16 KiB | 16 KiB | yes | 1.291 s | yes |
|
|
||||||
| Pre7 | 64 KiB | 64 KiB | yes | 1.438 s | yes |
|
|
||||||
| Pre7 | 1 MiB | 1 MiB | yes | 1.432 s | yes |
|
|
||||||
| Pre8 | 4 KiB | 4 KiB | yes | 1.216 s | yes |
|
|
||||||
| Pre8 | 16 KiB | 16 KiB | yes | 1.327 s | yes |
|
|
||||||
| Pre8 | 64 KiB | 64 KiB | yes | 1.430 s | yes |
|
|
||||||
| Pre8 | 1 MiB | 1 MiB | yes | 1.442 s | yes |
|
|
||||||
| Pre9 | 4 KiB | 4 KiB | yes | 1.791 s | yes |
|
|
||||||
| Pre9 | 16 KiB | 16 KiB | yes | 1.341 s | yes |
|
|
||||||
| Pre9 | 64 KiB | 64 KiB | yes | 1.374 s | yes |
|
|
||||||
| Pre9 | 1 MiB | 1 MiB | yes | 1.737 s | yes |
|
|
||||||
|
|
||||||
The target-file truss lines are preserved in
|
|
||||||
`pre9-manual-evidence/probe-summary.txt`. Dynamic-loader `pread()` calls are
|
|
||||||
not counted as target-file calls.
|
|
||||||
|
|
||||||
The 1 MiB `dd` results were:
|
|
||||||
|
|
||||||
- Pre7: 1 MiB in 0.195526 s.
|
|
||||||
- Pre8: 1 MiB in 0.179484 s.
|
|
||||||
- Pre9: 1 MiB in 0.367417 s.
|
|
||||||
|
|
||||||
These values are not stable enough for version performance ranking, but all
|
|
||||||
three bounded operations completed.
|
|
||||||
|
|
||||||
## Full SHA sample
|
|
||||||
|
|
||||||
| Version | State at sample | File offset | Kernel stack | Final hash |
|
|
||||||
| --- | --- | ---: | --- | --- |
|
|
||||||
| Pre7 | running (`RC`) | 1,245,184 | `lzma2_lzma -> erofs_xz_dec_microlzma_run -> lzma_decompress -> z_erofs_decompress -> z_erofs_do_read -> z_erofs_read_uio` | absent |
|
|
||||||
| Pre8 | running (`RC`) | 1,150,976 | same | absent |
|
|
||||||
| Pre9 | running (`RC`) | 1,044,480 | same | absent |
|
|
||||||
|
|
||||||
The stack is direct evidence of active CPU-side decompression, not an EROFS
|
|
||||||
lock wait. It does not by itself prove why decompression is slow. Combined with
|
|
||||||
the static review, the leading explanation remains repeated full mapped-extent
|
|
||||||
decompression as `z_erofs_read_uio()` segments reads at `MAXPHYS`. There is no
|
|
||||||
direct evidence here of an XZ infinite loop or an EROFS lock deadlock.
|
|
||||||
|
|
||||||
## Infrastructure integrity and cleanup
|
|
||||||
|
|
||||||
The base image SHA-256 before and after run3 was identical and matched the
|
|
||||||
expected value:
|
|
||||||
|
|
||||||
`67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef`
|
|
||||||
|
|
||||||
For each version, `umount`, `mdconfig -d` and `kldunload` returned zero. Each
|
|
||||||
QEMU PID was no longer alive and each overlay was deleted. The run3 result set
|
|
||||||
therefore supports successful test-VM cleanup. This report does not infer the
|
|
||||||
state of the unrelated long-lived guard VM and did not inspect or modify it.
|
|
||||||
|
|
||||||
## Required follow-up
|
|
||||||
|
|
||||||
A supplemental manual test is still required if full-file correctness must be
|
|
||||||
closed. It should run one full SHA with an explicit wall-clock deadline, record
|
|
||||||
start/end timestamps and exit status, capture `sha.out` before cleanup, compare
|
|
||||||
the hash to the source fixture, and separately record whether TERM/KILL was
|
|
||||||
used. Until then, full-file SHA correctness remains `BLOCKED`.
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
# Pre9 LZMA decoded extent cache
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
|
|
||||||
Pre7, Pre8, and Pre9 all reproduced the same LZMA read-liveness symptom. The
|
|
||||||
manual evidence shows that a single large read completes quickly while a full
|
|
||||||
file read made up of successive small reads remains in the LZMA decode path.
|
|
||||||
The source path creates and destroys a decoded extent for every mapped read;
|
|
||||||
the existing FreeBSD buffer cache only retains compressed block buffers.
|
|
||||||
|
|
||||||
A cache local to `z_erofs_read_uio()` would not cross the VOP/read boundary
|
|
||||||
between successive small user reads. Commit `61f4709` therefore kept one
|
|
||||||
decoded extent on each compressed-file vnode. Review found that retained
|
|
||||||
memory could then grow with the number of open vnodes. This follow-up moves
|
|
||||||
the cache to `struct erofs_mount`: each mount retains at most one decoded
|
|
||||||
extent until unmount, so ordinary open-file count cannot expand the cache.
|
|
||||||
A single entry can thrash between files and concurrent readers; that is an
|
|
||||||
accepted first-stage tradeoff.
|
|
||||||
|
|
||||||
The cache is deliberately limited to complete, non-partial MicroLZMA extents.
|
|
||||||
Partial references keep the existing path because their decoded length and
|
|
||||||
reference semantics are different. Other codecs are also unchanged in this
|
|
||||||
phase: the measured failure is LZMA-specific, and broadening the change would
|
|
||||||
make the validation and regression attribution less precise.
|
|
||||||
|
|
||||||
## Data and lifecycle
|
|
||||||
|
|
||||||
`struct erofs_zextent_cache` stores the decoded allocation and the mapping
|
|
||||||
identity needed to prove that it can be reused:
|
|
||||||
|
|
||||||
```c
|
|
||||||
struct erofs_zextent_cache {
|
|
||||||
void *data;
|
|
||||||
erofs_nid_t m_nid;
|
|
||||||
erofs_off_t m_pa;
|
|
||||||
erofs_off_t m_la;
|
|
||||||
uint64_t m_plen;
|
|
||||||
uint64_t m_llen;
|
|
||||||
unsigned int m_deviceid;
|
|
||||||
unsigned int m_flags;
|
|
||||||
unsigned char m_algorithmformat;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
The cache mutex is initialized immediately after allocating
|
|
||||||
`struct erofs_mount`. Every mount failure path reaches `erofs_sb_free()`, and
|
|
||||||
normal unmount calls the same helper after `vflush()`. There is no cache field
|
|
||||||
or cache lifecycle dependency in `struct erofs_node`. The cache key includes
|
|
||||||
the inode NID because one mount entry is shared by all regular file vnodes.
|
|
||||||
NID zero remains a valid key; `data != NULL` is the validity bit.
|
|
||||||
|
|
||||||
EROFS is read-only, so a decoded extent does not need write invalidation.
|
|
||||||
`vflush()` completes before unmount frees the mount object, and
|
|
||||||
`z_erofs_extent_cache_fini()` releases the single mount-owned allocation.
|
|
||||||
`EROFS_MAP_META` is explicitly excluded, so metadata-backed tailpacking keeps
|
|
||||||
the previous path. `packed_inode` and `metabox_en` are also excluded because
|
|
||||||
they are mount-private backing objects, not user file vnodes.
|
|
||||||
|
|
||||||
## Concurrency
|
|
||||||
|
|
||||||
Decompression and block reads occur without holding `z_extent_cache_lock`. A reader
|
|
||||||
first takes the lock only to compare the complete key and copy a cache hit.
|
|
||||||
On a miss, it builds a private decoded extent. It then takes the lock again:
|
|
||||||
|
|
||||||
1. If another reader published the same key, copy that published extent and
|
|
||||||
discard the duplicate private allocation.
|
|
||||||
2. Otherwise replace the one cached extent, copy the requested range, unlock,
|
|
||||||
and free the old allocation.
|
|
||||||
|
|
||||||
This permits duplicate construction under concurrent misses but keeps all
|
|
||||||
shared pointer access under the mutex. The lock is never held across
|
|
||||||
`bread()`, allocation, or decompression, all of which may sleep. The cache
|
|
||||||
allocation is never freed while a reader is copying it because replacement,
|
|
||||||
hit copying, and pointer clearing are serialized by the same mutex.
|
|
||||||
|
|
||||||
The helpers are reached only when `want <= MAXPHYS` and contain `KASSERT`
|
|
||||||
checks for that contract. Thus the largest lock-held copy is the FreeBSD
|
|
||||||
`MAXPHYS` request size, not the 12 MiB on-disk extent cap. Calls that can pass
|
|
||||||
more than `MAXPHYS` use the existing uncached copy path. This bounded mutex
|
|
||||||
copy is accepted for the first stage; a refcounted immutable entry is deferred
|
|
||||||
until runtime evidence shows that this copy is materially contended.
|
|
||||||
|
|
||||||
## Bounds and unchanged paths
|
|
||||||
|
|
||||||
The existing mapping sanity checks cap a mapped compressed extent at
|
|
||||||
`Z_EROFS_PCLUSTER_MAX_DSIZE` before the read path. `z_erofs_read_extent()` also
|
|
||||||
checks the compressed and decoded lengths before allocation. The read path now
|
|
||||||
explicitly checks `mapoff` and the extent length before converting them to
|
|
||||||
`size_t`; this protects the cache offset arithmetic on platforms where
|
|
||||||
`size_t` is narrower than the on-disk fields.
|
|
||||||
|
|
||||||
Cache use requires all of the following:
|
|
||||||
|
|
||||||
```text
|
|
||||||
compressed mapped extent
|
|
||||||
not EROFS_MAP_PARTIAL_REF
|
|
||||||
Z_EROFS_COMPRESSION_LZMA
|
|
||||||
initialized mount cache
|
|
||||||
not `EROFS_MAP_META`
|
|
||||||
not a mount-private backing inode
|
|
||||||
request length no greater than `MAXPHYS`
|
|
||||||
```
|
|
||||||
|
|
||||||
Fragments, holes, partial references, non-LZMA codecs, uncompressed files,
|
|
||||||
metadata reads, and mount-private backing inodes retain their previous code
|
|
||||||
paths and error handling.
|
|
||||||
|
|
||||||
## Rejected alternatives for Pre9
|
|
||||||
|
|
||||||
- A function-local cache was rejected because it cannot span successive VOP
|
|
||||||
reads that caused the observed amplification.
|
|
||||||
- A per-vnode cache was rejected after the `61f4709` review: open file count
|
|
||||||
could retain one decoded extent per vnode without a system-wide bound.
|
|
||||||
- A larger cross-vnode cache was rejected because it would require an eviction
|
|
||||||
policy and larger memory accounting. The one-entry per-mount cache is the
|
|
||||||
controlled compromise: it has a fixed mount-scoped bound and simple teardown.
|
|
||||||
- A Linux page/folio/XArray/workqueue port was rejected because those are not
|
|
||||||
FreeBSD vnode/buf primitives and would create an unnecessary compatibility
|
|
||||||
layer.
|
|
||||||
- A decoder stream pool was deferred: it may reduce allocator overhead but
|
|
||||||
does not remove repeated full extent decompression.
|
|
||||||
- Changing `MAXPHYS`, changing the disk format, bypassing the buffer cache, or
|
|
||||||
adding decoder retries was rejected because none addresses the demonstrated
|
|
||||||
decoded-result reuse and each changes unrelated behavior or resource bounds.
|
|
||||||
|
|
||||||
## Static validation and required runtime matrix
|
|
||||||
|
|
||||||
This change is static-only in the source phase. The follow-up test agent must
|
|
||||||
run the unchanged LZMA fixture against Pre9 and require:
|
|
||||||
|
|
||||||
1. bounded single reads at 4 KiB, 16 KiB, 64 KiB, and 1 MiB with source-range
|
|
||||||
hash equality;
|
|
||||||
2. repeated small reads spanning the same extent, with completion and hash
|
|
||||||
equality;
|
|
||||||
3. complete sequential SHA-256 with recorded exit status and elapsed time;
|
|
||||||
4. concurrent reads of the same file and close/reopen reads;
|
|
||||||
5. partial-reference, plain, LZ4, DEFLATE, and ZSTD regression coverage;
|
|
||||||
6. clean unmount, md detach, and module unload after every case.
|
|
||||||
|
|
||||||
The automation verdict and DUT verdict must remain separate. A timeout or
|
|
||||||
missing final hash remains a failure or blocked result; it must not be promoted
|
|
||||||
to PASS because bounded reads succeed.
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# Pre9 LZMA cache review resolution
|
|
||||||
|
|
||||||
This document records the follow-up to commit `61f4709`, which cached one
|
|
||||||
decoded LZMA extent per vnode.
|
|
||||||
|
|
||||||
## Findings addressed
|
|
||||||
|
|
||||||
- The cache is now one entry in `struct erofs_mount`, rather than one entry in
|
|
||||||
every `struct erofs_node`. Retained decoded memory is bounded by one extent
|
|
||||||
per mounted filesystem, with the number of mounts controlled by mount
|
|
||||||
privileges. Keeping many ordinary file descriptors open cannot create more
|
|
||||||
cache entries.
|
|
||||||
- Cache initialization is performed in `erofs_mountfs()` immediately after
|
|
||||||
mount allocation. `erofs_sb_free()` destroys it on every mount failure path
|
|
||||||
and after successful `vflush()` during unmount. Node reclaim no longer owns
|
|
||||||
cache cleanup.
|
|
||||||
- `EROFS_MAP_META` is an explicit ineligibility condition. Metadata-backed
|
|
||||||
tailpacking therefore remains on its existing read path.
|
|
||||||
- `packed_inode` and `metabox_en` are explicit ineligibility conditions. The
|
|
||||||
mount-private backing objects cannot populate or consume the user-data
|
|
||||||
cache.
|
|
||||||
- The cache type and helper names are now `erofs_zextent_cache` and
|
|
||||||
`z_erofs_extent_cache_*`, distinguishing decoded extents from Linux's
|
|
||||||
managed compressed-page cache names.
|
|
||||||
- The key retains the existing physical/logical extent fields, device id,
|
|
||||||
flags, and algorithm, and adds the stable inode `nid`. The `data` pointer is
|
|
||||||
the validity bit, so NID zero is not treated as an empty key.
|
|
||||||
|
|
||||||
## Copy bound and concurrency
|
|
||||||
|
|
||||||
`z_erofs_read_uio()` limits each output request to `MAXPHYS`. The generic
|
|
||||||
`z_erofs_read_data()` API can receive a larger request, so cache eligibility
|
|
||||||
rejects any request whose mapped portion exceeds `MAXPHYS`. Both cache helper
|
|
||||||
entry points also contain `KASSERT(len <= MAXPHYS)` checks. The largest copy
|
|
||||||
performed while holding `z_extent_cache_lock` is therefore `MAXPHYS`; the
|
|
||||||
12 MiB `Z_EROFS_PCLUSTER_MAX_DSIZE` limit remains an on-disk decoded-extent
|
|
||||||
allocation bound, not a mutex-copy bound.
|
|
||||||
|
|
||||||
Allocation, compressed reads, and decompression happen outside the mutex. A
|
|
||||||
cache hit copies while holding the mutex, and a miss publishes and copies
|
|
||||||
under the same mutex before the previous allocation is freed. Concurrent
|
|
||||||
misses may decode duplicate extents and may replace one another, but pointer
|
|
||||||
access and replacement remain serialized. A refcounted immutable cache entry
|
|
||||||
was deliberately not introduced in this first stage.
|
|
||||||
|
|
||||||
## Resource tradeoff
|
|
||||||
|
|
||||||
The per-mount entry is intentionally a small first-stage design. It removes
|
|
||||||
the unbounded-per-open-vnode retention introduced by `61f4709`, but it can
|
|
||||||
thrash when many files are read concurrently on one mount. Retention lasts
|
|
||||||
until unmount, and the retained allocation is capped by the existing EROFS
|
|
||||||
format constant `Z_EROFS_PCLUSTER_MAX_DSIZE` (12 MiB). A FreeBSD shrinker or
|
|
||||||
pressure callback is deferred; adding one would require a broader memory
|
|
||||||
accounting and lifecycle design than this corrective commit.
|
|
||||||
|
|
||||||
## Validation scope
|
|
||||||
|
|
||||||
This correction is statically validated only. QEMU validation remains
|
|
||||||
required for complete SHA-256 reads, same-file concurrent reads, close/reopen,
|
|
||||||
unmount cleanup, metadata tailpacking, and memory-pressure behavior. The
|
|
||||||
existing Pre9 manual test report predates this correction and must not be
|
|
||||||
reported as runtime validation of this commit.
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
Run3 full-file SHA samples, captured approximately eight seconds after launch
|
|
||||||
|
|
||||||
repo-pre-7
|
|
||||||
state: RC
|
|
||||||
file offset: 1245184
|
|
||||||
kernel stack: lzma2_lzma -> erofs_xz_dec_microlzma_run -> lzma_decompress -> z_erofs_decompress -> z_erofs_do_read -> z_erofs_read_uio -> VOP_READ_APV -> vn_read
|
|
||||||
sha_after: no process row, no sha.out hash, no sha.err content
|
|
||||||
termination: TERM sent; KILL then reported No such process
|
|
||||||
|
|
||||||
repo-pre-8
|
|
||||||
state: RC
|
|
||||||
file offset: 1150976
|
|
||||||
kernel stack: lzma2_lzma -> erofs_xz_dec_microlzma_run -> lzma_decompress -> z_erofs_decompress -> z_erofs_do_read -> z_erofs_read_uio -> VOP_READ_APV -> vn_read
|
|
||||||
sha_after: no process row, no sha.out hash, no sha.err content
|
|
||||||
termination: TERM sent; KILL then reported No such process
|
|
||||||
|
|
||||||
repo-pre-9
|
|
||||||
state: RC
|
|
||||||
file offset: 1044480
|
|
||||||
kernel stack: lzma2_lzma -> erofs_xz_dec_microlzma_run -> lzma_decompress -> z_erofs_decompress -> z_erofs_do_read -> z_erofs_read_uio -> VOP_READ_APV -> vn_read
|
|
||||||
sha_after: no process row, no sha.out hash, no sha.err content
|
|
||||||
termination: TERM sent; KILL then reported No such process
|
|
||||||
|
|
||||||
Interpretation: the SHA processes were alive and executing in LZMA decode at
|
|
||||||
the sample. Their later disappearance does not prove successful completion.
|
|
||||||
No full-file hash was captured, so full-file correctness remains BLOCKED.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
Pre9 final decoded extent cache kernel and cleanup summary
|
|
||||||
Date: 2026-08-13
|
|
||||||
|
|
||||||
- Guest: FreeBSD 15.0-RELEASE-p8 amd64, QEMU TCG, 6144 MiB, 4 vCPUs.
|
|
||||||
- KLD built with WITH_ZSTDIO=0 and loaded successfully.
|
|
||||||
- No EROFS panic, assertion, mount error or decompression error appeared in
|
|
||||||
the captured dmesg tail.
|
|
||||||
- Boot emitted pre-existing root-filesystem "bad dir ino" warnings before
|
|
||||||
the test KLD was loaded; these are not attributed to EROFS.
|
|
||||||
- Explicit LZMA probe, LZMA full-read and LZ4 unmount/md detach operations
|
|
||||||
returned zero.
|
|
||||||
- Test QEMU PID 812999 was terminated.
|
|
||||||
- Host port 10030 was closed.
|
|
||||||
- Test overlay was removed.
|
|
||||||
- Guard QEMU PID 26318 remained alive.
|
|
||||||
- Guard SSH port 9222 remained open.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
Pre9 final decoded extent cache target-file syscall evidence
|
|
||||||
Date: 2026-08-13
|
|
||||||
|
|
||||||
4 KiB:
|
|
||||||
pread(3, ..., 4096, 0x0) = 4096 (0x1000)
|
|
||||||
output/source SHA-256: 1c3c59331a4849514667bbc51c078327577b98f75a62996bbc2fe310b014dd79
|
|
||||||
|
|
||||||
16 KiB:
|
|
||||||
pread(3, ..., 16384, 0x0) = 16384 (0x4000)
|
|
||||||
output/source SHA-256: 2433ce7c2ea151f487a319447ce4fe14e1a2c2af9f0e5113fe47fc74b6138eee
|
|
||||||
|
|
||||||
64 KiB:
|
|
||||||
pread(3, ..., 65536, 0x0) = 65536 (0x10000)
|
|
||||||
output/source SHA-256: 2bb87afd3b9fab420cbe55b782d69a7342150e8816a35efacf22d2ab3012815d
|
|
||||||
|
|
||||||
1 MiB:
|
|
||||||
pread(3, ..., 1048576, 0x0) = 1048576 (0x100000)
|
|
||||||
output/source SHA-256: 52e806509e5dfeb523904f167fca765d001ea749351ecf51738e61a5352a1ba3
|
|
||||||
|
|
||||||
Each trace contained exactly one pread() against the mounted target file.
|
|
||||||
Dynamic-loader pread() calls were excluded from this summary.
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"archive_sha256": "a6a6d573ace42fe713529974c7bd20b472a1e4521920fac40e01c5d3bb071bcb",
|
|
||||||
"cleanup": {
|
|
||||||
"guard_pid_alive": true,
|
|
||||||
"guard_port_9222_open": true,
|
|
||||||
"overlay_exists": false,
|
|
||||||
"port_10030_open": false,
|
|
||||||
"qemu_pid_alive": false
|
|
||||||
},
|
|
||||||
"finished_utc": "2026-08-13T06:06:25Z",
|
|
||||||
"kld_sha256": "473a6205f43905972f2417609d43f67ab2cb51ea79bc1716fffa5c1914ff85af",
|
|
||||||
"lz4_sha": {
|
|
||||||
"expected_sha256": "3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880",
|
|
||||||
"guest_real_seconds": 9.03,
|
|
||||||
"hash_match": true,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880"
|
|
||||||
},
|
|
||||||
"lzma_concurrent": {
|
|
||||||
"guest_real_seconds": [
|
|
||||||
22.52,
|
|
||||||
21.97
|
|
||||||
],
|
|
||||||
"hash_match": true,
|
|
||||||
"hashes": [
|
|
||||||
"ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461",
|
|
||||||
"ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461"
|
|
||||||
],
|
|
||||||
"host_timeout": false,
|
|
||||||
"returncode": 0,
|
|
||||||
"returncodes": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lzma_fixture": {
|
|
||||||
"image_sha256": "32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9",
|
|
||||||
"source_sha256": "ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461"
|
|
||||||
},
|
|
||||||
"lzma_sha": {
|
|
||||||
"cold": {
|
|
||||||
"guest_real_seconds": 2.16,
|
|
||||||
"hash_match": true,
|
|
||||||
"host_timeout": false,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461"
|
|
||||||
},
|
|
||||||
"warm": {
|
|
||||||
"guest_real_seconds": 1.44,
|
|
||||||
"hash_match": true,
|
|
||||||
"host_timeout": false,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"repo_pre_9_tree": "9d7eaf63a1c5d07320af3ef39930fc0a3530dd11",
|
|
||||||
"schema": "pre9-cache-final-manual-v1",
|
|
||||||
"single_pread": [
|
|
||||||
{
|
|
||||||
"elapsed_seconds": 2.696,
|
|
||||||
"hash_match": true,
|
|
||||||
"length": 4096,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "1c3c59331a4849514667bbc51c078327577b98f75a62996bbc2fe310b014dd79"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"elapsed_seconds": 2.14,
|
|
||||||
"hash_match": true,
|
|
||||||
"length": 16384,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "2433ce7c2ea151f487a319447ce4fe14e1a2c2af9f0e5113fe47fc74b6138eee"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"elapsed_seconds": 1.369,
|
|
||||||
"hash_match": true,
|
|
||||||
"length": 65536,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "2bb87afd3b9fab420cbe55b782d69a7342150e8816a35efacf22d2ab3012815d"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"elapsed_seconds": 3.838,
|
|
||||||
"hash_match": true,
|
|
||||||
"length": 1048576,
|
|
||||||
"returncode": 0,
|
|
||||||
"sha256": "52e806509e5dfeb523904f167fca765d001ea749351ecf51738e61a5352a1ba3"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"src_tree": "e657e8a63b097b061670f75ca01947a568ef33d5",
|
|
||||||
"started_utc": "2026-08-13T05:59:41Z",
|
|
||||||
"tested_head": "cdcf276d12169a672d2de42996532a470ac061d9",
|
|
||||||
"verdict": {
|
|
||||||
"build_load_mount": "PASS",
|
|
||||||
"cleanup": "PASS",
|
|
||||||
"lzma_concurrency": "PASS",
|
|
||||||
"lzma_full_correctness": "PASS",
|
|
||||||
"lzma_liveness_performance": "PASS",
|
|
||||||
"lzma_single_pread_correctness": "PASS",
|
|
||||||
"non_lzma_lz4": "PASS"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
Run3 target-file syscall evidence (dynamic-loader pread calls omitted)
|
|
||||||
|
|
||||||
repo-pre-7
|
|
||||||
4096: pread(fd, ..., 4096, 0) = 4096; process exit 0
|
|
||||||
16384: pread(fd, ..., 16384, 0) = 16384; process exit 0
|
|
||||||
65536: pread(fd, ..., 65536, 0) = 65536; process exit 0
|
|
||||||
1048576: pread(fd, ..., 1048576, 0) = 1048576; process exit 0
|
|
||||||
|
|
||||||
repo-pre-8
|
|
||||||
4096: pread(fd, ..., 4096, 0) = 4096; process exit 0
|
|
||||||
16384: pread(fd, ..., 16384, 0) = 16384; process exit 0
|
|
||||||
65536: pread(fd, ..., 65536, 0) = 65536; process exit 0
|
|
||||||
1048576: pread(fd, ..., 1048576, 0) = 1048576; process exit 0
|
|
||||||
|
|
||||||
repo-pre-9
|
|
||||||
4096: pread(fd, ..., 4096, 0) = 4096; process exit 0
|
|
||||||
16384: pread(fd, ..., 16384, 0) = 16384; process exit 0
|
|
||||||
65536: pread(fd, ..., 65536, 0) = 65536; process exit 0
|
|
||||||
1048576: pread(fd, ..., 1048576, 0) = 1048576; process exit 0
|
|
||||||
|
|
||||||
All mounted-output hashes matched corresponding source-range hashes. The full
|
|
||||||
hash values and elapsed times are retained in run3-audit.json.
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"base_image": {
|
|
||||||
"before": "67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef",
|
|
||||||
"after": "67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef",
|
|
||||||
"expected": "67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef",
|
|
||||||
"unchanged": true
|
|
||||||
},
|
|
||||||
"fixture": {
|
|
||||||
"image_sha256": "32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9",
|
|
||||||
"source_sha256": "ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461"
|
|
||||||
},
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"name": "repo-pre-7",
|
|
||||||
"repository_tree": "b8f9af2cd55225c4348b79ff5910ae6fc83cd517",
|
|
||||||
"src_tree": "dc203534d7b5721905f8538026e4c59346106020",
|
|
||||||
"kld_sha256": "33a52f2f16a94afda0501d305b238678b96c71e420d4b8bbcbeec6ffcdf1aae5",
|
|
||||||
"probes": [
|
|
||||||
{"length": 4096, "returned": 4096, "elapsed_seconds": 1.2993653398007154, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 16384, "returned": 16384, "elapsed_seconds": 1.2910558842122555, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 65536, "returned": 65536, "elapsed_seconds": 1.4380157887935638, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 1048576, "returned": 1048576, "elapsed_seconds": 1.4320225361734629, "hash_match": true, "target_pread_count": 1}
|
|
||||||
],
|
|
||||||
"dd_1m_seconds": 0.195526,
|
|
||||||
"sha_sample_offset": 1245184,
|
|
||||||
"sha_hash_captured": false,
|
|
||||||
"cleanup": {"umount": 0, "mdconfig_detach": 0, "kldunload": 0, "qemu_alive": false, "overlay_exists": false}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "repo-pre-8",
|
|
||||||
"repository_tree": "1e24c992a5b071e6fdabfdc42d342b6ed5a91cf5",
|
|
||||||
"src_tree": "cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2",
|
|
||||||
"kld_sha256": "348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0",
|
|
||||||
"probes": [
|
|
||||||
{"length": 4096, "returned": 4096, "elapsed_seconds": 1.2161498833447695, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 16384, "returned": 16384, "elapsed_seconds": 1.3266378343105316, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 65536, "returned": 65536, "elapsed_seconds": 1.4296557288616896, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 1048576, "returned": 1048576, "elapsed_seconds": 1.4422911144793034, "hash_match": true, "target_pread_count": 1}
|
|
||||||
],
|
|
||||||
"dd_1m_seconds": 0.179484,
|
|
||||||
"sha_sample_offset": 1150976,
|
|
||||||
"sha_hash_captured": false,
|
|
||||||
"cleanup": {"umount": 0, "mdconfig_detach": 0, "kldunload": 0, "qemu_alive": false, "overlay_exists": false}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "repo-pre-9",
|
|
||||||
"repository_tree": "dc0c01157b5c925684bd77c57ed6703904af7453",
|
|
||||||
"src_tree": "cbf93a19df8d1ce2fb66e2aeb7276a4ea6d4dcc2",
|
|
||||||
"kld_sha256": "348cb1f5a91d47e1412747d285c795c49375a61a66cfb3d35d22f38ecfde6ea0",
|
|
||||||
"probes": [
|
|
||||||
{"length": 4096, "returned": 4096, "elapsed_seconds": 1.7912541721016169, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 16384, "returned": 16384, "elapsed_seconds": 1.341409295797348, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 65536, "returned": 65536, "elapsed_seconds": 1.3740410972386599, "hash_match": true, "target_pread_count": 1},
|
|
||||||
{"length": 1048576, "returned": 1048576, "elapsed_seconds": 1.737462431192398, "hash_match": true, "target_pread_count": 1}
|
|
||||||
],
|
|
||||||
"dd_1m_seconds": 0.367417,
|
|
||||||
"sha_sample_offset": 1044480,
|
|
||||||
"sha_hash_captured": false,
|
|
||||||
"cleanup": {"umount": 0, "mdconfig_detach": 0, "kldunload": 0, "qemu_alive": false, "overlay_exists": false}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# repo22 Linux/FreeBSD 结构对齐维护计划
|
|
||||||
|
|
||||||
## 基线
|
|
||||||
|
|
||||||
- FreeBSD 实现:`src/`
|
|
||||||
- Linux 参考:`/work/dev-src-linux/fs/erofs`(Linux 7.1-rc1 快照)
|
|
||||||
- 比较方法:逐文件和逐职责比较,不依赖共同 Git 历史
|
|
||||||
- 运行目标:FreeBSD 15 amd64
|
|
||||||
|
|
||||||
## 决策规则
|
|
||||||
|
|
||||||
1. 先判断差异是否来自 FreeBSD vnode、GEOM、errno、锁或内核库接口。
|
|
||||||
2. 只对非必要差异调整静态函数名、变量名、定义顺序和文件职责。
|
|
||||||
3. 不为匹配 Linux 文件表而添加空模块或不适用的抽象。
|
|
||||||
4. `src/Makefile` 是模块名、源码清单、架构门控和编译选项的权威来源。
|
|
||||||
5. 构建产物、生成头和机器 include symlink 不进入版本控制。
|
|
||||||
|
|
||||||
## 本轮清单
|
|
||||||
|
|
||||||
- [x] 清除受跟踪的 `build/obj` 生成头和机器 symlink
|
|
||||||
- [x] 精确忽略模块构建及手工测试生成目录
|
|
||||||
- [x] 由原生 `bsd.kmod.mk` 取代手写 amd64 clang/link 流程
|
|
||||||
- [x] 明确拒绝未验证的非 amd64 架构
|
|
||||||
- [x] 将 ZSTDIO 配置统一为 `WITH_ZSTDIO=0/1`
|
|
||||||
- [x] 按 Linux 顺序整理 Makefile 源码列表
|
|
||||||
- [x] 对齐 `find_target_dirent` 和 `decompressor_*.c` 名称
|
|
||||||
- [x] 将跨文件解压后端声明集中到 `internal.h`
|
|
||||||
- [x] 保留 BSD 专属 `erofs_vnops.c`、`lz4.c` 和后端调用契约
|
|
||||||
- [x] 在 FreeBSD 15 VM 完成双配置构建和 ZSTD 挂载 smoke
|
|
||||||
|
|
||||||
## 验证门槛
|
|
||||||
|
|
||||||
1. `WITH_ZSTDIO=0` 与 `WITH_ZSTDIO=1` 均从空对象目录构建。
|
|
||||||
2. 禁用产物不含 `ZSTD_*` 未解析符号,启用产物必须含预期内核 API。
|
|
||||||
3. 启用产物完成加载、ZSTD 镜像挂载、文件读取、卸载和 KLD 清理。
|
|
||||||
4. 非 `amd64` 和非法 `WITH_ZSTDIO` 值必须明确失败。
|
|
||||||
5. 提交只包含 repo22 pathspec,且远端 `xdm/main` 与本地 HEAD 一致。
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# repo22 Linux/FreeBSD 结构对齐状态
|
|
||||||
|
|
||||||
## 已完成
|
|
||||||
|
|
||||||
- 使用 `/work/dev-src-linux/fs/erofs` 的 Linux 7.1-rc1 快照逐文件复核;未使用
|
|
||||||
两个实现共享历史的假设。
|
|
||||||
- `namei.c` 的静态 helper 已从 `erofs_find_target_dirent` 恢复为 Linux 名称
|
|
||||||
`find_target_dirent`。
|
|
||||||
- `lzma.c`、`deflate.c`、`zstd.c` 已按 Linux 职责名调整为
|
|
||||||
`decompressor_lzma.c`、`decompressor_deflate.c`、
|
|
||||||
`decompressor_zstd.c`。
|
|
||||||
- 解压后端原型已移入 `internal.h`;MicroLZMA 内嵌 XZ 的 allocator helper
|
|
||||||
已限制为编译单元内部符号。
|
|
||||||
- `src/Makefile` 已按 Linux 的 metadata、压缩调度/映射、算法后端顺序组织,
|
|
||||||
并成为 `build.sh` 的唯一源码和模块名来源。
|
|
||||||
- 受跟踪的对象目录、vnode 生成头和 amd64/x86 机器 symlink 已删除并忽略。
|
|
||||||
|
|
||||||
## 保留差异
|
|
||||||
|
|
||||||
- `erofs_vnops.c` 承载 FreeBSD vnode、pager、NFS 和只读操作语义。
|
|
||||||
- `lz4.c` 保持独立,因为 BSD 后端不使用 Linux page/LZ4 调度接口。
|
|
||||||
- 后端函数保持 BSD 内部 API,而不是复制 Linux decompressor descriptor 和
|
|
||||||
page 生命周期。
|
|
||||||
- FreeBSD 路径返回正 errno,并保留 GEOM/provider、lockmgr 和 vnode 规则。
|
|
||||||
- Linux `sysfs`、file-backed、fscache、page-cache sharing 和 `zutil` 职责不以
|
|
||||||
空文件模拟。
|
|
||||||
- 当前构建门控仅允许已验证的 FreeBSD 15 `amd64`。
|
|
||||||
|
|
||||||
## 2026-08-09 验证
|
|
||||||
|
|
||||||
- VM:FreeBSD `15.0-RELEASE-p8` amd64。
|
|
||||||
- 构建源:FreeBSD `15.0 RELEASE-p9` `sys` 树。
|
|
||||||
- `WITH_ZSTDIO=0` 构建通过,模块 SHA256:
|
|
||||||
`d11d0319dc1d786eaa868a0c05c2abaf43da8480acacb0e1e4b72b7542b05432`;
|
|
||||||
无 `ZSTD_*` 未解析符号。
|
|
||||||
- `WITH_ZSTDIO=1` 构建通过,模块 SHA256:
|
|
||||||
`82471f19812e9877ea06901d1ba0cb4378b2bc6476ec70f6e024e0dc777c0c71`;
|
|
||||||
编译命令包含 `-DZSTDIO` 并引用 FreeBSD 内核 ZSTD API。
|
|
||||||
- 启用模块完成加载、`zstd-level1.erofs` 只读挂载、6 个文件读取与 SHA256、
|
|
||||||
卸载、md detach 和 KLD unload;测试后无遗留挂载或模块。
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Issue Status
|
|
||||||
|
|
||||||
This directory preserves both resolved investigations and approved validation
|
|
||||||
gaps. Resolved files remain historical evidence; they are not current failures.
|
|
||||||
|
|
||||||
| Issue | Status | Current conclusion |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [TC010 48-bit statfs](TC010-48bit-statfs-large-provider.md) | RESOLVED | A qualified 16 TiB-plus sparse provider completed mount and 64-bit `statfs` validation. |
|
|
||||||
| [TC060 pathconf](TC060-pathconf-standard-values.md) | RESOLVED | FreeBSD-standard values were implemented and dynamically revalidated. |
|
|
||||||
| [TC153 large directory index](TC153-large-directory-block-index-validation.md) | RESOLVED | The exact fixed KLD returned `EINTEGRITY` on the multi-TiB sparse-provider path. |
|
|
||||||
| [Explicit mapped extent payload](extent-metadata-fixture-unavailable.md) | SHELVED | TC146 remains PARTIAL because no independently validated positive mapped-payload fixture is available. |
|
|
||||||
|
|
||||||
The remaining shelved item records its trigger, affected feature, analysis,
|
|
||||||
attempts, results, progress, and acceptance criteria. It is a fixture/tooling
|
|
||||||
gap, not an observed kernel failure.
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
# TC010 48-bit statfs Large Provider
|
|
||||||
|
|
||||||
Status: **RESOLVED - qualified sparse vnode provider validated**
|
|
||||||
|
|
||||||
Resolved: 2026-08-09
|
|
||||||
|
|
||||||
Baseline: `cd0e985b5ac54a4b7acb7042422329ad1729fb3e`
|
|
||||||
|
|
||||||
## Original Problem
|
|
||||||
|
|
||||||
TC010 requires a real EROFS mount whose 48-bit superblock block count has a
|
|
||||||
nonzero high word. A nonzero `blocks_hi` declares at least `2^32` filesystem
|
|
||||||
blocks, so a 4 KiB filesystem needs a provider larger than 16 TiB. Earlier
|
|
||||||
vnode-md work used only small regular images and correctly could not claim PASS.
|
|
||||||
|
|
||||||
This affects:
|
|
||||||
|
|
||||||
- 48-bit superblock block-count decoding;
|
|
||||||
- primary-device media-size validation;
|
|
||||||
- FreeBSD `statfs(2)` and `df(1)` 64-bit totals;
|
|
||||||
- the union selector between `rb.blocks_hi` and `rb.rootnid_2b`.
|
|
||||||
|
|
||||||
## Exact Trigger
|
|
||||||
|
|
||||||
1. `EROFS_FEATURE_INCOMPAT_48BIT` is set.
|
|
||||||
2. `rootnid_8b` is nonzero, selecting `rb.blocks_hi`.
|
|
||||||
3. `blocks_hi` is nonzero.
|
|
||||||
4. Provider media size is at least `total_blocks << blkszbits`.
|
|
||||||
5. Superblock CRC32C, root inode, and normal mount checks pass.
|
|
||||||
|
|
||||||
A short provider fails with `ENXIO`; that negative guard cannot replace the
|
|
||||||
positive statfs test. TC150's `rootnid_8b == 0` fallback and multidevice totals
|
|
||||||
also select different production paths.
|
|
||||||
|
|
||||||
## Earlier Attempts
|
|
||||||
|
|
||||||
1. Structured metadata patching and CRC32C recomputation succeeded.
|
|
||||||
2. The normal small vnode provider failed media-size validation as expected.
|
|
||||||
3. Static source comparison confirmed Linux's `48BIT && rootnid_8b` selector,
|
|
||||||
but static arithmetic was not counted as dynamic coverage.
|
|
||||||
4. No earlier run had attached and mounted a qualified 16 TiB provider, so the
|
|
||||||
issue remained SHELVED.
|
|
||||||
|
|
||||||
## Resolution
|
|
||||||
|
|
||||||
The isolated FreeBSD 15.0-RELEASE-p8 guest uses UFS2, which supports a sparse
|
|
||||||
regular file large enough for vnode md without allocating 16 TiB physically:
|
|
||||||
|
|
||||||
```text
|
|
||||||
truncate -s 17592193667072 TC010-provider.raw
|
|
||||||
stat: size=17592193667072 allocated_blocks=15232 block_size=32768
|
|
||||||
mdconfig -a -t vnode -f TC010-provider.raw: md0
|
|
||||||
diskinfo mediasize: 17592193667072 bytes
|
|
||||||
```
|
|
||||||
|
|
||||||
The structured fixture encoded:
|
|
||||||
|
|
||||||
```text
|
|
||||||
blocks_lo=1861
|
|
||||||
blocks_hi=1
|
|
||||||
rootnid_8b=36
|
|
||||||
total_blocks=4294969157
|
|
||||||
required_provider_length=17592193667072
|
|
||||||
```
|
|
||||||
|
|
||||||
Prefix SHA256:
|
|
||||||
`d3ffadc6fc9e73f85a8a5973b4ac5ee2a2da57b4e8baeccd259fa4325a2146cf`.
|
|
||||||
|
|
||||||
The exact prefix was copied to the sparse provider, then extended with zeros.
|
|
||||||
Mount succeeded with KLD SHA256
|
|
||||||
`8349c97c7ced253fff32a9e706f29313f309cb63a270e4e39a4501426f2b95c6`.
|
|
||||||
`df` reported:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Filesystem Type 1024-blocks Used Avail Capacity
|
|
||||||
/dev/md0 erofs 17179876628 17179876628 0 100%
|
|
||||||
```
|
|
||||||
|
|
||||||
`17179876628 == 4294969157 * 4`; no 32-bit wrap occurred. `f_bfree` and
|
|
||||||
available blocks were zero, so Used correctly equaled total. The control file
|
|
||||||
matched, dmesg had no new fault, and the mount, md unit, sparse provider, and
|
|
||||||
KLD were cleaned up.
|
|
||||||
|
|
||||||
## Related Coverage
|
|
||||||
|
|
||||||
- TC017 separately repeated the small-provider `ENXIO` guard and qualified
|
|
||||||
sparse-provider mount, proving the nonzero high-word parse dynamically.
|
|
||||||
- TC018 separately read exact bytes from physical offset
|
|
||||||
`17592191561728`, above 16 TiB; it did not substitute a large `df` result for
|
|
||||||
high-address data I/O.
|
|
||||||
|
|
||||||
No repo22 kernel source change was made during this resolution.
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# TC060 Standard pathconf Values
|
|
||||||
|
|
||||||
Status: **RESOLVED - standard FreeBSD pathconf values validated**
|
|
||||||
|
|
||||||
Last updated: 2026-08-09
|
|
||||||
|
|
||||||
Resolved: 2026-08-09
|
|
||||||
|
|
||||||
Priority: High
|
|
||||||
|
|
||||||
Implementation status: Fixed by `cdba7e54fb9e9d82980a06f178e68d0bbc1663ac`
|
|
||||||
and dynamically validated
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
The exact repo22 9ae22009f KLD returns EINVAL for two standard pathconf names on
|
|
||||||
an otherwise valid mounted EROFS directory:
|
|
||||||
|
|
||||||
- _PC_NO_TRUNC
|
|
||||||
- _PC_CHOWN_RESTRICTED
|
|
||||||
|
|
||||||
The same call correctly returns NAME_MAX=255, PATH_MAX=1024,
|
|
||||||
FILESIZEBITS=64, and LINK_MAX=2147483647. TC060 therefore fails at the kernel
|
|
||||||
behavior level; this is not a missing guest tool or fixture limitation.
|
|
||||||
|
|
||||||
## Trigger and Evidence
|
|
||||||
|
|
||||||
Environment:
|
|
||||||
|
|
||||||
- FreeBSD 15.0-RELEASE-p8 amd64 guest on port 9222.
|
|
||||||
- Exact source commit: 9ae22009f23a65320730072a780998e80aa9b728.
|
|
||||||
- KLD SHA256:
|
|
||||||
19ad086bd2508cbb4c57b1a51f38c93057d438b84fbcfa2e637ff2519f5bc590.
|
|
||||||
- Fixture: vfs-plain.erofs SHA256
|
|
||||||
79f0b5f4aa8e7ea532b711ee8fb466f14f35d0952446d41ba4bbc4d6e008b8ff.
|
|
||||||
|
|
||||||
Direct command:
|
|
||||||
|
|
||||||
/tmp/repo22-g3/g3_vfs_probe pathconf \
|
|
||||||
/tmp/repo22-g3/mnt/testdir
|
|
||||||
|
|
||||||
Observed output and process status:
|
|
||||||
|
|
||||||
name_max=255 path_max=1024 filesizebits=64 link_max=2147483647 \
|
|
||||||
no_trunc=error:22 chown_restricted=error:22
|
|
||||||
g3_vfs_probe: unexpected EROFS pathconf values
|
|
||||||
probe_status=1
|
|
||||||
|
|
||||||
The test used a fresh dynamic md0, a read-only EROFS mount, and the exact KLD.
|
|
||||||
After capture, umount and md detach both returned zero. Final guest state was
|
|
||||||
zero EROFS mounts, zero md units, and no loaded EROFS KLD.
|
|
||||||
|
|
||||||
## Analysis
|
|
||||||
|
|
||||||
erofs_pathconf() handles NAME_MAX, PATH_MAX, FILESIZEBITS, LINK_MAX, and ACL
|
|
||||||
queries directly, then delegates other names to vop_stdpathconf(). In this
|
|
||||||
FreeBSD 15 configuration the delegation returns EINVAL for both names above.
|
|
||||||
The mounted filesystem is immutable and enforces 255-byte names, so reporting
|
|
||||||
NO_TRUNC=1 and CHOWN_RESTRICTED=1 is consistent with the implemented behavior
|
|
||||||
and with the TC contract.
|
|
||||||
|
|
||||||
This failure affects applications that use pathconf(2) to discover pathname
|
|
||||||
truncation and ownership-change restrictions. It does not affect the four
|
|
||||||
values that repo22 already handles directly.
|
|
||||||
|
|
||||||
## Original Required Resolution
|
|
||||||
|
|
||||||
Add explicit FreeBSD vnode pathconf handling for both standard names, then
|
|
||||||
rerun TC060 with the direct syscall helper. Acceptance requires both values to
|
|
||||||
be 1, all six queries to have errno 0, unchanged mount/read behavior, no new
|
|
||||||
dmesg diagnostics, and complete mount/md/KLD cleanup.
|
|
||||||
|
|
||||||
## Resolution
|
|
||||||
|
|
||||||
FreeBSD 15's `vop_stdpathconf()` intentionally provides only generic values
|
|
||||||
such as `_PC_ASYNC_IO`, `_PC_PATH_MAX`, and zero-valued optional features; its
|
|
||||||
default case returns `EINVAL`. UFS, tmpfs, and ext2fs therefore implement
|
|
||||||
`_PC_CHOWN_RESTRICTED` and `_PC_NO_TRUNC` in their filesystem pathconf methods
|
|
||||||
before delegating all remaining names to `vop_stdpathconf()`.
|
|
||||||
|
|
||||||
EROFS now follows that FreeBSD pattern: the two names return 1, while the
|
|
||||||
existing NAME_MAX, PATH_MAX, FILESIZEBITS, LINK_MAX, and ACL cases remain
|
|
||||||
unchanged and the default branch still calls `vop_stdpathconf()`. This matches
|
|
||||||
the implemented filesystem behavior: uid/gid mutation is rejected with EROFS,
|
|
||||||
and lookup of a component longer than `EROFS_NAME_LEN` returns ENAMETOOLONG.
|
|
||||||
No lock, allocation, reference, or cleanup path was added.
|
|
||||||
|
|
||||||
Linux EROFS was used only as a maintenance comparison for the 255-byte name
|
|
||||||
limit and ENAMETOOLONG behavior. FreeBSD 15 VOP and syscall semantics were the
|
|
||||||
authority for the returned values and errno behavior.
|
|
||||||
|
|
||||||
## Qualified Retest
|
|
||||||
|
|
||||||
The exact source archive for the fix commit built natively on FreeBSD
|
|
||||||
15.0-RELEASE-p8 with kernel `-Werror` in both configurations:
|
|
||||||
|
|
||||||
- `WITH_ZSTDIO=0`: KLD SHA256
|
|
||||||
`68536e03ce93c6c04aab9cf29dab81ee5802d4b94401bd1a4bd752de40c0e504`.
|
|
||||||
- `WITH_ZSTDIO=1`: KLD SHA256
|
|
||||||
`598f171d355af78c64407a6d513d20f053530620da92df7f8ccfdf9a804e463d`.
|
|
||||||
|
|
||||||
The dependency-minimal `WITH_ZSTDIO=0` KLD and the original TC060 helper
|
|
||||||
reported:
|
|
||||||
|
|
||||||
```text
|
|
||||||
name_max=255 path_max=1024 filesizebits=64 link_max=2147483647
|
|
||||||
no_trunc=1 chown_restricted=1
|
|
||||||
```
|
|
||||||
|
|
||||||
All six queries had errno 0. Additional direct checks returned ASYNC_IO=200112,
|
|
||||||
ACL_EXTENDED=1, ACL_PATH_MAX=254, and ACL_NFS4=0 with errno 0. An unknown name
|
|
||||||
returned `-1/EINVAL(22)`, and a 256-byte component returned
|
|
||||||
`ENAMETOOLONG(63)`. The mounted file hash and read-only EROFS behavior were
|
|
||||||
unchanged, dmesg was byte-identical before and after, and final mount/md/KLD
|
|
||||||
and guest artifact counts were zero.
|
|
||||||
|
|
||||||
Complete build, value, smoke, discarded-attempt, review, and cleanup evidence
|
|
||||||
is in
|
|
||||||
`tests/results/manual/2026-08-09T1120Z-tc060-fix/manual-test-report.md`.
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
# TC153 Large Directory Block Index Validation
|
|
||||||
|
|
||||||
Status: **RESOLVED - exact-source kernel validation passed**
|
|
||||||
|
|
||||||
Last updated: 2026-08-09
|
|
||||||
|
|
||||||
Priority: Critical validation gap
|
|
||||||
|
|
||||||
Implementation status: Source fix present, build-verified, and dynamically
|
|
||||||
validated
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
`erofs_find_target_block()` used signed `int` values for the binary-search
|
|
||||||
front, back, and midpoint indexes. A directory whose logical size describes
|
|
||||||
`2147483649` 4 KiB blocks produces a final block index of `2147483648`.
|
|
||||||
Converting that value to `int` can make the initial back bound negative. The
|
|
||||||
search can then return `ENOENT` without reading any directory block, and the
|
|
||||||
FreeBSD namecache can retain a false negative result for corrupt media.
|
|
||||||
|
|
||||||
The review change uses `uint64_t` for block-search bounds and midpoints, checks
|
|
||||||
the midpoint multiplication, and handles the `mid == 0` lower-bound case. The
|
|
||||||
within-block search remains `uint32_t` because a validated EROFS directory
|
|
||||||
block can contain only a block-sized number of entries.
|
|
||||||
|
|
||||||
## Affected Features
|
|
||||||
|
|
||||||
- Cold pathname lookup in very large or maliciously sized directories.
|
|
||||||
- Corruption reporting and `EINTEGRITY` propagation from directory reads.
|
|
||||||
- Negative namecache correctness after a failed lookup.
|
|
||||||
- Linux/FreeBSD behavioral review of EROFS's two-level directory search.
|
|
||||||
|
|
||||||
Normal directories are not expected to approach this bound. The practical
|
|
||||||
risk is a crafted image causing an incorrect `ENOENT`, not an ordinary mkfs
|
|
||||||
image losing entries.
|
|
||||||
|
|
||||||
## Trigger Conditions
|
|
||||||
|
|
||||||
All of the following are needed to exercise the original width error:
|
|
||||||
|
|
||||||
1. A directory inode is accepted with a logical block count greater than
|
|
||||||
`INT_MAX`.
|
|
||||||
2. The directory layout reaches `erofs_find_target_block()` rather than being
|
|
||||||
rejected by an earlier inline-data bounds check.
|
|
||||||
3. A cold lookup is issued for a name that is not satisfied by an already
|
|
||||||
cached vnode or negative namecache entry.
|
|
||||||
4. The backing image is too short for the computed midpoint read, so the fixed
|
|
||||||
code should return `EINTEGRITY` instead of a synthetic miss.
|
|
||||||
|
|
||||||
For 4 KiB blocks, TC153 encodes a size of `8796093026304` bytes,
|
|
||||||
`2147483649` blocks, and a final index of `2147483648`.
|
|
||||||
|
|
||||||
## Current Analysis
|
|
||||||
|
|
||||||
The source change is mechanically narrow and has passed both repo22 build
|
|
||||||
configurations. The checked multiplication protects a future block-size or
|
|
||||||
index change even though the current `OFF_MAX` inode limit already bounds the
|
|
||||||
product. The `mid == 0` guard prevents unsigned subtraction from wrapping when
|
|
||||||
the search moves below the first block.
|
|
||||||
|
|
||||||
Dynamic proof must show more than a large `st_size`. It must prove that the
|
|
||||||
lookup enters the block binary search. An image rejected in
|
|
||||||
`erofs_read_inode()` is not evidence for this fix, and an `ENOENT` observed
|
|
||||||
after a warm negative cache is ambiguous.
|
|
||||||
|
|
||||||
## Attempts and Results
|
|
||||||
|
|
||||||
### Attempt 1: Small FLAT_INLINE image
|
|
||||||
|
|
||||||
- Artifact directory:
|
|
||||||
`/work/build/repo22-review-artifact.LtqNxH`
|
|
||||||
- Base image: `large-dir-base.erofs`, 4096 bytes, SHA256
|
|
||||||
`973d2a1c90ac1bf776ed76a1fc6a7e88b2156fac3bf04ddbae19cfafebbd562e`
|
|
||||||
- Patched image: `large-dir-intmax.erofs`, 4096 bytes, SHA256
|
|
||||||
`ce5cad3eff34ea50ca89eedf93d8ef90e6cea96858a138685fae45f39084de1f`
|
|
||||||
- Recorded inode: NID 40 at byte 1280.
|
|
||||||
|
|
||||||
The directory was Layout 2 (`FLAT_INLINE`). Patching only `i_size` made its
|
|
||||||
declared inline tail range invalid, so inode validation rejected it before
|
|
||||||
`erofs_find_target_block()`. This attempt is invalid as TC153 dynamic evidence
|
|
||||||
and must never be marked PASS.
|
|
||||||
|
|
||||||
### Attempt 2: More entries to force block data
|
|
||||||
|
|
||||||
- Artifact directory:
|
|
||||||
`/work/build/repo22-review-artifact2.FmMTup`
|
|
||||||
- Generated base: `large-dir-base.erofs`, 65536 bytes, SHA256
|
|
||||||
`50eb28351788ab1801408aca0a6fca6352755f5ca56efe6e2bb3e2fe08305663`
|
|
||||||
- Directory: NID 40, 21052 bytes, still Layout 2.
|
|
||||||
|
|
||||||
The generation process was interrupted before producing a patched image or a
|
|
||||||
FreeBSD result. A later deterministic rerun reproduced the same base hash and
|
|
||||||
showed why the approach failed: erofs-utils 1.8.6 tail-packs directories even
|
|
||||||
when they span multiple data blocks. Its `noinline_data` option does not turn
|
|
||||||
directory tail packing off.
|
|
||||||
|
|
||||||
### Attempt 3: Follow-up agents
|
|
||||||
|
|
||||||
Multiple follow-up agents were assigned the fixture and guest validation.
|
|
||||||
They either stopped while preparing the second image or returned no executed
|
|
||||||
commands, files, hashes, or guest output. These attempts added no evidence and
|
|
||||||
are recorded to prevent their elapsed time from being mistaken for progress.
|
|
||||||
|
|
||||||
### Attempt 4: Sparse-provider design
|
|
||||||
|
|
||||||
A guest-side sparse vnode provider was considered so a valid directory could
|
|
||||||
declare the complete multi-terabyte range. It was not executed. Such a scheme
|
|
||||||
must prove the GEOM media size, avoid materializing terabytes, preserve valid
|
|
||||||
initial directory blocks, and still force a cold read at the binary-search
|
|
||||||
midpoint. No result exists for this approach.
|
|
||||||
|
|
||||||
### Attempt 5: Reproducible FLAT_PLAIN conversion
|
|
||||||
|
|
||||||
The tracked generator now copies all 21052 bytes of the generated directory
|
|
||||||
to appended blocks, changes only that inode to Layout 0 (`FLAT_PLAIN`), updates
|
|
||||||
the image block count and CRC32C, and then applies the large logical size.
|
|
||||||
|
|
||||||
Host reproduction on 2026-08-09 produced:
|
|
||||||
|
|
||||||
- `large-dir-base.erofs`: 65536 bytes, SHA256
|
|
||||||
`50eb28351788ab1801408aca0a6fca6352755f5ca56efe6e2bb3e2fe08305663`
|
|
||||||
- `large-dir-intmax.erofs`: 90112 bytes, SHA256
|
|
||||||
`0f90d3d57adbbbd946e41b225c1f6c464915c6abb0b13478ec9b2a318def1f72`
|
|
||||||
- Patched inode: NID 40 at byte 1280, Layout 0, raw block 16.
|
|
||||||
- Declared image blocks: 22.
|
|
||||||
|
|
||||||
This resolved the fixture-construction problem. The qualified kernel run is
|
|
||||||
recorded below.
|
|
||||||
|
|
||||||
### Attempt 6: Qualified sparse GEOM provider
|
|
||||||
|
|
||||||
The G3 takeover generated a checksum-valid sparse prefix from Attempt 5 and
|
|
||||||
performed one targeted FreeBSD 15 run against the exact source requested by
|
|
||||||
the assignment.
|
|
||||||
|
|
||||||
- Source commit:
|
|
||||||
9ae22009f23a65320730072a780998e80aa9b728.
|
|
||||||
- KLD SHA256:
|
|
||||||
19ad086bd2508cbb4c57b1a51f38c93057d438b84fbcfa2e637ff2519f5bc590.
|
|
||||||
- Sparse-prefix SHA256:
|
|
||||||
f9337f83b1f568f6d904331a7749e6362a691055cd5af95b59bc89772f04e3b0.
|
|
||||||
- Prefix qualification: NID 40, inode offset 1280, extended Layout 0,
|
|
||||||
start block 16, 2147483649 directory blocks, final block index 2147483648,
|
|
||||||
valid superblock checksum.
|
|
||||||
- Sparse provider: 8796093091840 logical bytes, 448 allocated 512-byte
|
|
||||||
sectors, and the first 90112 bytes retained the prefix SHA256.
|
|
||||||
- GEOM diskinfo size: 8796093091840 bytes.
|
|
||||||
- Mounted /huge: size 8796093026304, NID 40.
|
|
||||||
|
|
||||||
The first two cold stat operations for /huge/missing each returned EINTEGRITY
|
|
||||||
(97). Root readdir then returned three complete entries and validated all
|
|
||||||
kernel/libc restart cookies. A third lookup after that readdir again returned
|
|
||||||
EINTEGRITY. No lookup returned ENOENT, so no false negative namecache entry
|
|
||||||
masked the corruption.
|
|
||||||
|
|
||||||
Unmount, md detach, sparse-provider removal, and KLD unload all succeeded.
|
|
||||||
The only new dmesg lines in the complete G3 run were expected SIGBUS child
|
|
||||||
exits from the unrelated assigned mmap tests; TC153 added no diagnostic.
|
|
||||||
|
|
||||||
## Historical Remaining Validation
|
|
||||||
|
|
||||||
Attempt 6 completed steps 1-5 and 7 below. The assignment mandated the exact
|
|
||||||
fixed source, so the optional pre-fix comparison in step 6 was not run.
|
|
||||||
|
|
||||||
1. Regenerate the images with
|
|
||||||
`tests/results/manual/2026-08-09T0124Z-final-review/prepare-fixtures.sh` and
|
|
||||||
verify the hashes and Layout 0 assertion.
|
|
||||||
2. Load the exact module under test in a clean FreeBSD 15 guest.
|
|
||||||
3. Mount the 90112-byte image and confirm `/huge` reports
|
|
||||||
`8796093026304` bytes.
|
|
||||||
4. With a cold parent cache, run two lookups of `/huge/missing` and capture
|
|
||||||
direct command exit codes plus `truss` errno.
|
|
||||||
5. Require `EINTEGRITY` on every fixed-module lookup, including after root
|
|
||||||
readdir. Confirm no negative cache changes the result.
|
|
||||||
6. Repeat with the pre-fix module to demonstrate the erroneous `ENOENT` path.
|
|
||||||
7. Record dmesg, mount/md/KLD cleanup, module and fixture hashes in a dated
|
|
||||||
manual report.
|
|
||||||
|
|
||||||
## Original Acceptance Criteria
|
|
||||||
|
|
||||||
TC153 can move from SHELVED to PASS only after the fixed FreeBSD KLD returns
|
|
||||||
`EINTEGRITY` repeatedly from the valid Layout 0 fixture, the pre-fix behavior
|
|
||||||
is distinguished, no trap or panic occurs, and complete cleanup evidence is
|
|
||||||
recorded. Host fixture generation and static source review alone are
|
|
||||||
insufficient.
|
|
||||||
|
|
||||||
## Resolution
|
|
||||||
|
|
||||||
TC153 is PASS because the exact fixed FreeBSD KLD returned EINTEGRITY
|
|
||||||
repeatedly from the valid Layout 0 fixture before and after root readdir, no
|
|
||||||
trap or panic occurred, and complete hash/provider/cleanup evidence is recorded
|
|
||||||
in tests/results/manual/2026-08-09T1059Z-g3/manual-test-report.md. Host fixture
|
|
||||||
generation and static source review alone remain insufficient.
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
# Explicit Extent Metadata Fixture Unavailable
|
|
||||||
|
|
||||||
Status: **SHELVED - positive mapped payload unavailable**
|
|
||||||
|
|
||||||
Last updated: 2026-08-09, final aggregation
|
|
||||||
|
|
||||||
Latest reviewed baseline: `fcc85b93d5f8fd9671686bd68bf3b086c8bd25cf`
|
|
||||||
|
|
||||||
Priority: High validation gap
|
|
||||||
|
|
||||||
Implementation status: ABI and control flow implemented; positive mapped
|
|
||||||
kernel read pending
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
repo22 implements the newer compressed-extent metadata path selected by
|
|
||||||
`Z_EROFS_ADVISE_EXTENTS`. Dynamic positive validation requires an image with a
|
|
||||||
valid extent table that maps a real payload. erofs-utils 1.8.6 cannot emit or
|
|
||||||
validate this on-disk format, and the repository's structured helpers cannot
|
|
||||||
currently relocate a legacy compressed inode into a validated positive extent
|
|
||||||
table.
|
|
||||||
|
|
||||||
HEAD2, interlaced pclusters, legacy full/compact indexes, partial references,
|
|
||||||
fragments, and all four decoders have separate dynamic coverage. None of those
|
|
||||||
substitutes for entering `z_erofs_map_blocks_ext()` with a mapped payload.
|
|
||||||
|
|
||||||
## Required Trigger
|
|
||||||
|
|
||||||
1. The inode uses compressed-full layout.
|
|
||||||
2. The map header sets `Z_EROFS_ADVISE_EXTENTS`.
|
|
||||||
3. The selected 4-, 8-, 16-, or 32-byte records form a complete valid table.
|
|
||||||
4. Physical fields identify real payload bytes for the declared algorithm.
|
|
||||||
5. Logical starts, physical lengths, partial flags, and final-record semantics
|
|
||||||
agree with the source file.
|
|
||||||
6. A FreeBSD read reaches the explicit mapper and returns source-identical
|
|
||||||
bytes.
|
|
||||||
|
|
||||||
Zero-count tables, overflowing physical bases, holes, and ordinary full-index
|
|
||||||
images are negative or adjacent coverage, not this trigger.
|
|
||||||
|
|
||||||
## G5 Independent Attempts
|
|
||||||
|
|
||||||
All inputs below were generated in new G5 output directories. No old image or
|
|
||||||
report was consumed as a fixture.
|
|
||||||
|
|
||||||
### 1. erofs-utils 1.8.6 capability scan
|
|
||||||
|
|
||||||
Observed tool output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
mkfs.erofs (erofs-utils) 1.8.6
|
|
||||||
available compressors: lz4, lz4hc, lzma, deflate, libdeflate, zstd
|
|
||||||
```
|
|
||||||
|
|
||||||
The helper searched the installed 1.8.6 `include/` and `lib/` trees for these
|
|
||||||
on-disk symbols:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Z_EROFS_ADVISE_EXTENTS: 0 matches
|
|
||||||
z_erofs_extent_recsize: 0 matches
|
|
||||||
struct z_erofs_extent {: 0 matches
|
|
||||||
```
|
|
||||||
|
|
||||||
The mkfs help has no explicit-record option. `--max-extent-bytes` only limits
|
|
||||||
decompressed extent size.
|
|
||||||
|
|
||||||
Result: **generator unavailable**.
|
|
||||||
|
|
||||||
### 2. `--max-extent-bytes` generation attempt
|
|
||||||
|
|
||||||
`g5_fixtures.py` generated a fresh LZ4 full-index image with:
|
|
||||||
|
|
||||||
```text
|
|
||||||
-zlz4 -C65536 -Elegacy-compress --max-extent-bytes=65536
|
|
||||||
```
|
|
||||||
|
|
||||||
Structured reopen and `dump.erofs` produced:
|
|
||||||
|
|
||||||
```text
|
|
||||||
image = images/extent-attempt.erofs
|
|
||||||
image SHA256 = ee7472c23ccffd5eef6f4a3171ea53ae2e840f8a1ea417b2630065175ecf3225
|
|
||||||
source SHA256 = 5be510e6b43f1ed0cda4261288ea70df11607b6ced29bc90d32ed2849ecc5e35
|
|
||||||
inode layout = 1 (compressed full)
|
|
||||||
map header offset = 1312
|
|
||||||
h_advise = 2
|
|
||||||
HEAD1 algorithm = 0 (LZ4)
|
|
||||||
explicit bit selected = no
|
|
||||||
```
|
|
||||||
|
|
||||||
`h_advise=2` is ordinary HEAD1 big-pcluster metadata. Naming or sizing the
|
|
||||||
image as an extent attempt does not enter the explicit mapper.
|
|
||||||
|
|
||||||
Result: **not an explicit fixture**.
|
|
||||||
|
|
||||||
### 3. Structured conversion attempt
|
|
||||||
|
|
||||||
The G5 transformer parsed the source inode, map header, full lcluster indexes,
|
|
||||||
physical extents, and payload bounds. It refused to emit a purported positive
|
|
||||||
fixture because conversion requires relocating variable-size extent records,
|
|
||||||
subsequent inode metadata, and possibly payload blocks. erofs-utils 1.8.6
|
|
||||||
cannot reopen and validate the resulting ABI, so an ad hoc rewrite would not
|
|
||||||
provide trustworthy evidence.
|
|
||||||
|
|
||||||
The existing `tests/review_fixtures.py` helper was also reviewed. Its
|
|
||||||
`extent-pa-wrap.erofs` conversion deliberately writes two 4-byte records and a
|
|
||||||
physical base whose `pa + plen` overflows. That is a negative overflow trigger
|
|
||||||
for TC155. It does not describe a valid mapped payload and cannot close this
|
|
||||||
issue.
|
|
||||||
|
|
||||||
Result: **structured positive conversion unavailable**.
|
|
||||||
|
|
||||||
### 4. ABI and control-flow comparison
|
|
||||||
|
|
||||||
The G5 review compared repo22 `src/erofs_fs.h`/`src/zmap.c` with the Linux EROFS
|
|
||||||
definitions and mapper. Both sides define:
|
|
||||||
|
|
||||||
- record sizes 4, 8, 16, and 32 bytes;
|
|
||||||
- implicit 64-bit physical bases for 4-byte records;
|
|
||||||
- per-record low physical starts for 8-byte records;
|
|
||||||
- explicit counts and binary search for 16/32-byte records;
|
|
||||||
- high physical and logical words where the record size carries them;
|
|
||||||
- partial-reference, shifted/interlaced format, and final fragment handling;
|
|
||||||
- malformed-count and arithmetic bounds checks.
|
|
||||||
|
|
||||||
This reduces implementation risk but is static evidence only.
|
|
||||||
|
|
||||||
## Impact
|
|
||||||
|
|
||||||
- TC146 HEAD2: dynamic PASS.
|
|
||||||
- TC146 interlaced: dynamic PASS.
|
|
||||||
- TC146 explicit mapped payload: SHELVED.
|
|
||||||
- TC146 overall: **PARTIAL**, never overall PASS while this issue remains.
|
|
||||||
- Record-size variants, positive binary-search transitions, mapped high words,
|
|
||||||
and explicit-record partial references remain dynamically unvalidated.
|
|
||||||
|
|
||||||
No repo22 kernel source was changed because this is a fixture/tooling gap, not
|
|
||||||
an observed kernel failure.
|
|
||||||
|
|
||||||
## Progress
|
|
||||||
|
|
||||||
- [x] Reproduce tool limitation against exactly erofs-utils 1.8.6.
|
|
||||||
- [x] Record tool output and zero symbol matches.
|
|
||||||
- [x] Generate and inspect a fresh `--max-extent-bytes` attempt.
|
|
||||||
- [x] Record source/image hashes and map-header fields.
|
|
||||||
- [x] Audit the existing structured negative helper.
|
|
||||||
- [x] Compare FreeBSD and Linux record layouts/control flow.
|
|
||||||
- [x] Reject globally unordered 16-byte and 32-byte explicit tables through
|
|
||||||
TC157 on FreeBSD 15 without reading the referenced payload.
|
|
||||||
- [ ] Obtain a producer or validator for positive mapped extent records.
|
|
||||||
- [ ] Generate at least one source-identical mapped payload.
|
|
||||||
- [ ] Cover 4/8/16/32-byte positive records where applicable.
|
|
||||||
- [ ] Exercise binary-search transitions, partial refs, high words, and final
|
|
||||||
fragments dynamically.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
This issue can close only after a reproducible helper emits a valid mapped
|
|
||||||
compressed payload, records its structural fields and hashes, validates it
|
|
||||||
with an independent format-aware implementation, and FreeBSD full/boundary
|
|
||||||
reads match the source. Negative overflow/hole fixtures and static review do
|
|
||||||
not satisfy acceptance.
|
|
||||||
|
|
||||||
## Final Residual Risk
|
|
||||||
|
|
||||||
TC157 closes the known binary-search ordering bug for descending, duplicate,
|
|
||||||
and cross-branch 16-byte and 32-byte tables. It does not supply the missing
|
|
||||||
positive mapped payload, dynamically cover every record-size variant, or
|
|
||||||
benchmark extremely large extent counts. Those limits do not change the issue
|
|
||||||
status or TC146's PARTIAL result.
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
# Basic .clang-format
|
|
||||||
---
|
|
||||||
BasedOnStyle: WebKit
|
|
||||||
AlignAfterOpenBracket: DontAlign
|
|
||||||
AlignConsecutiveMacros: AcrossEmptyLines
|
|
||||||
AlignConsecutiveAssignments: false
|
|
||||||
AlignConsecutiveDeclarations: false
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AlignOperands: false
|
|
||||||
AlignTrailingComments: true
|
|
||||||
AllowAllArgumentsOnNextLine: false
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
|
||||||
AllowShortBlocksOnASingleLine: Never
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: MultiLine
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeBraces: WebKit
|
|
||||||
BreakBeforeTernaryOperators: false
|
|
||||||
# TODO: BreakStringLiterals can cause very strange formatting so turn it off?
|
|
||||||
BreakStringLiterals: false
|
|
||||||
# Prefer:
|
|
||||||
# some_var = function(arg1,
|
|
||||||
# arg2)
|
|
||||||
# over:
|
|
||||||
# some_var =
|
|
||||||
# function(arg1, arg2)
|
|
||||||
PenaltyBreakAssignment: 100
|
|
||||||
# Prefer:
|
|
||||||
# some_long_function(arg1, arg2
|
|
||||||
# arg3)
|
|
||||||
# over:
|
|
||||||
# some_long_function(
|
|
||||||
# arg1, arg2, arg3)
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 100
|
|
||||||
CompactNamespaces: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
ForEachMacros:
|
|
||||||
- ARB_ARRFOREACH
|
|
||||||
- ARB_ARRFOREACH_REVWCOND
|
|
||||||
- ARB_ARRFOREACH_REVERSE
|
|
||||||
- ARB_FOREACH
|
|
||||||
- ARB_FOREACH_FROM
|
|
||||||
- ARB_FOREACH_SAFE
|
|
||||||
- ARB_FOREACH_REVERSE
|
|
||||||
- ARB_FOREACH_REVERSE_FROM
|
|
||||||
- ARB_FOREACH_REVERSE_SAFE
|
|
||||||
- BIT_FOREACH_ISCLR
|
|
||||||
- BIT_FOREACH_ISSET
|
|
||||||
- CPU_FOREACH
|
|
||||||
- CPU_FOREACH_ISCLR
|
|
||||||
- CPU_FOREACH_ISSET
|
|
||||||
- FOREACH_THREAD_IN_PROC
|
|
||||||
- FOREACH_PROC_IN_SYSTEM
|
|
||||||
- FOREACH_PRISON_CHILD
|
|
||||||
- FOREACH_PRISON_DESCENDANT
|
|
||||||
- FOREACH_PRISON_DESCENDANT_LOCKED
|
|
||||||
- FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL
|
|
||||||
- MNT_VNODE_FOREACH_ALL
|
|
||||||
- MNT_VNODE_FOREACH_ACTIVE
|
|
||||||
- RB_FOREACH
|
|
||||||
- RB_FOREACH_FROM
|
|
||||||
- RB_FOREACH_SAFE
|
|
||||||
- RB_FOREACH_REVERSE
|
|
||||||
- RB_FOREACH_REVERSE_FROM
|
|
||||||
- RB_FOREACH_REVERSE_SAFE
|
|
||||||
- SLIST_FOREACH
|
|
||||||
- SLIST_FOREACH_FROM
|
|
||||||
- SLIST_FOREACH_FROM_SAFE
|
|
||||||
- SLIST_FOREACH_SAFE
|
|
||||||
- SLIST_FOREACH_PREVPTR
|
|
||||||
- SPLAY_FOREACH
|
|
||||||
- LIST_FOREACH
|
|
||||||
- LIST_FOREACH_FROM
|
|
||||||
- LIST_FOREACH_FROM_SAFE
|
|
||||||
- LIST_FOREACH_SAFE
|
|
||||||
- STAILQ_FOREACH
|
|
||||||
- STAILQ_FOREACH_FROM
|
|
||||||
- STAILQ_FOREACH_FROM_SAFE
|
|
||||||
- STAILQ_FOREACH_SAFE
|
|
||||||
- TAILQ_FOREACH
|
|
||||||
- TAILQ_FOREACH_FROM
|
|
||||||
- TAILQ_FOREACH_FROM_SAFE
|
|
||||||
- TAILQ_FOREACH_REVERSE
|
|
||||||
- TAILQ_FOREACH_REVERSE_FROM
|
|
||||||
- TAILQ_FOREACH_REVERSE_FROM_SAFE
|
|
||||||
- TAILQ_FOREACH_REVERSE_SAFE
|
|
||||||
- TAILQ_FOREACH_SAFE
|
|
||||||
- VM_MAP_ENTRY_FOREACH
|
|
||||||
- VM_PAGE_DUMP_FOREACH
|
|
||||||
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentPPDirectives: None
|
|
||||||
Language: Cpp
|
|
||||||
NamespaceIndentation: None
|
|
||||||
PointerAlignment: Right
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
IndentWidth: 8
|
|
||||||
TabWidth: 8
|
|
||||||
ColumnLimit: 80
|
|
||||||
UseTab: Always
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
IncludeBlocks: Regroup
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^\"opt_.*\.h\"'
|
|
||||||
Priority: 1
|
|
||||||
SortPriority: 10
|
|
||||||
- Regex: '^<sys/cdefs\.h>'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 20
|
|
||||||
- Regex: '^<sys/types\.h>'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 21
|
|
||||||
- Regex: '^<sys/param\.h>'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 22
|
|
||||||
- Regex: '^<sys/systm\.h>'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 23
|
|
||||||
- Regex: '^<sys.*/'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 24
|
|
||||||
- Regex: '^<vm/vm\.h>'
|
|
||||||
Priority: 3
|
|
||||||
SortPriority: 30
|
|
||||||
- Regex: '^<vm/'
|
|
||||||
Priority: 3
|
|
||||||
SortPriority: 31
|
|
||||||
- Regex: '^<machine/'
|
|
||||||
Priority: 4
|
|
||||||
SortPriority: 40
|
|
||||||
- Regex: '^<(x86|amd64|i386|xen)/'
|
|
||||||
Priority: 5
|
|
||||||
SortPriority: 50
|
|
||||||
- Regex: '^<dev/'
|
|
||||||
Priority: 6
|
|
||||||
SortPriority: 60
|
|
||||||
- Regex: '^<net.*/'
|
|
||||||
Priority: 7
|
|
||||||
SortPriority: 70
|
|
||||||
- Regex: '^<protocols/'
|
|
||||||
Priority: 7
|
|
||||||
SortPriority: 71
|
|
||||||
- Regex: '^<(fs|nfs(|client|server)|ufs)/'
|
|
||||||
Priority: 8
|
|
||||||
SortPriority: 80
|
|
||||||
- Regex: '^<[^/].*\.h'
|
|
||||||
Priority: 9
|
|
||||||
SortPriority: 90
|
|
||||||
- Regex: '^\".*\.h\"'
|
|
||||||
Priority: 10
|
|
||||||
SortPriority: 100
|
|
||||||
# LLVM's header include ordering style is almost the exact opposite of ours.
|
|
||||||
# Unfortunately, they have hard-coded their preferences into clang-format.
|
|
||||||
# Clobbering this regular expression to avoid matching prevents non-system
|
|
||||||
# headers from being forcibly moved to the top of the include list.
|
|
||||||
# http://llvm.org/docs/CodingStandards.html#include-style
|
|
||||||
IncludeIsMainRegex: 'BLAH_DONT_MATCH_ANYTHING'
|
|
||||||
SortIncludes: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
|
||||||
TypenameMacros:
|
|
||||||
- ARB_ELMTYPE
|
|
||||||
- ARB_HEAD
|
|
||||||
- ARB8_HEAD
|
|
||||||
- ARB16_HEAD
|
|
||||||
- ARB32_HEAD
|
|
||||||
- ARB_ENTRY
|
|
||||||
- ARB8_ENTRY
|
|
||||||
- ARB16_ENTRY
|
|
||||||
- ARB32_ENTRY
|
|
||||||
- LIST_CLASS_ENTRY
|
|
||||||
- LIST_CLASS_HEAD
|
|
||||||
- LIST_ENTRY
|
|
||||||
- LIST_HEAD
|
|
||||||
- QUEUE_TYPEOF
|
|
||||||
- RB_ENTRY
|
|
||||||
- RB_HEAD
|
|
||||||
- SLIST_CLASS_HEAD
|
|
||||||
- SLIST_CLASS_ENTRY
|
|
||||||
- SLIST_HEAD
|
|
||||||
- SLIST_ENTRY
|
|
||||||
- SMR_POINTER
|
|
||||||
- SPLAY_ENTRY
|
|
||||||
- SPLAY_HEAD
|
|
||||||
- STAILQ_CLASS_ENTRY
|
|
||||||
- STAILQ_CLASS_HEAD
|
|
||||||
- STAILQ_ENTRY
|
|
||||||
- STAILQ_HEAD
|
|
||||||
- TAILQ_CLASS_ENTRY
|
|
||||||
- TAILQ_CLASS_HEAD
|
|
||||||
- TAILQ_ENTRY
|
|
||||||
- TAILQ_HEAD
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
|
|
||||||
i386
|
|
||||||
machine
|
|
||||||
x86
|
|
||||||
.cache
|
|
||||||
|
|
||||||
export_syms
|
|
||||||
|
|
||||||
*.o
|
|
||||||
*.ko
|
|
||||||
|
|
||||||
opt_global.h
|
|
||||||
|
|
||||||
vnode_if.h
|
|
||||||
vnode_if_newproto.h
|
|
||||||
vnode_if_typedef.h
|
|
||||||
|
|
||||||
compile_commands.json
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Comprehensive decompression unit tests for repo19
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
TESTDIR="/tmp/repo19_decompress_tests"
|
|
||||||
SRCDIR="/work/repo-community/repo19/src"
|
|
||||||
RESULTS_FILE="/tmp/test_results.txt"
|
|
||||||
|
|
||||||
mkdir -p "$TESTDIR"
|
|
||||||
cd "$TESTDIR"
|
|
||||||
|
|
||||||
echo "==================================================================="
|
|
||||||
echo " REPO19 DECOMPRESSION COMPREHENSIVE UNIT TESTS"
|
|
||||||
echo "==================================================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Test counters
|
|
||||||
TOTAL=0
|
|
||||||
PASSED=0
|
|
||||||
FAILED=0
|
|
||||||
|
|
||||||
# Track results
|
|
||||||
> "$RESULTS_FILE"
|
|
||||||
|
|
||||||
test_case() {
|
|
||||||
local name="$1"
|
|
||||||
local result="$2"
|
|
||||||
local error="$3"
|
|
||||||
|
|
||||||
TOTAL=$((TOTAL + 1))
|
|
||||||
if [ "$result" = "PASS" ]; then
|
|
||||||
PASSED=$((PASSED + 1))
|
|
||||||
echo "✓ $name" >> "$RESULTS_FILE"
|
|
||||||
printf "%-60s [PASS]\n" "$name"
|
|
||||||
else
|
|
||||||
FAILED=$((FAILED + 1))
|
|
||||||
echo "✗ $name: $error" >> "$RESULTS_FILE"
|
|
||||||
printf "%-60s [FAIL] %s\n" "$name" "$error"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate test data files
|
|
||||||
generate_test_data() {
|
|
||||||
echo "Generating test data..."
|
|
||||||
|
|
||||||
# Small file (512B)
|
|
||||||
dd if=/dev/zero of=small_512b.dat bs=512 count=1 2>/dev/null
|
|
||||||
|
|
||||||
# Medium file (4KB)
|
|
||||||
dd if=/dev/urandom of=medium_4k.dat bs=4096 count=1 2>/dev/null
|
|
||||||
|
|
||||||
# Medium-large (32KB)
|
|
||||||
dd if=/dev/urandom of=medium_32k.dat bs=32768 count=1 2>/dev/null
|
|
||||||
|
|
||||||
# Large file (64KB)
|
|
||||||
dd if=/dev/urandom of=large_64k.dat bs=65536 count=1 2>/dev/null
|
|
||||||
|
|
||||||
# 1MB file
|
|
||||||
dd if=/dev/urandom of=large_1m.dat bs=1048576 count=1 2>/dev/null
|
|
||||||
|
|
||||||
# Highly compressible (zeros)
|
|
||||||
dd if=/dev/zero of=compressible_8k.dat bs=8192 count=1 2>/dev/null
|
|
||||||
|
|
||||||
# Text data
|
|
||||||
for i in {1..1000}; do echo "The quick brown fox jumps over the lazy dog."; done > text_data.txt
|
|
||||||
|
|
||||||
# Random incompressible
|
|
||||||
dd if=/dev/urandom of=random_16k.dat bs=16384 count=1 2>/dev/null
|
|
||||||
|
|
||||||
echo "Test data generated."
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# LZ4 Tests
|
|
||||||
test_lz4() {
|
|
||||||
echo "--- LZ4 TESTS ---"
|
|
||||||
|
|
||||||
# Test 1: Small file
|
|
||||||
if lz4 -c small_512b.dat > small_512b.lz4 2>/dev/null; then
|
|
||||||
if lz4 -d -c small_512b.lz4 > small_512b.out 2>/dev/null && cmp -s small_512b.dat small_512b.out; then
|
|
||||||
test_case "LZ4: small file (512B)" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZ4: small file (512B)" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZ4: small file (512B)" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 2: Medium file (4KB)
|
|
||||||
if lz4 -c medium_4k.dat > medium_4k.lz4 2>/dev/null; then
|
|
||||||
if lz4 -d -c medium_4k.lz4 > medium_4k.out 2>/dev/null && cmp -s medium_4k.dat medium_4k.out; then
|
|
||||||
test_case "LZ4: medium file (4KB)" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZ4: medium file (4KB)" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZ4: medium file (4KB)" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 3: Large file (64KB)
|
|
||||||
if lz4 -c large_64k.dat > large_64k.lz4 2>/dev/null; then
|
|
||||||
if lz4 -d -c large_64k.lz4 > large_64k.out 2>/dev/null && cmp -s large_64k.dat large_64k.out; then
|
|
||||||
test_case "LZ4: large file (64KB)" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZ4: large file (64KB)" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZ4: large file (64KB)" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 4: 1MB performance
|
|
||||||
if lz4 -c large_1m.dat > large_1m.lz4 2>/dev/null; then
|
|
||||||
START=$(date +%s%N)
|
|
||||||
if lz4 -d -c large_1m.lz4 > large_1m.out 2>/dev/null && cmp -s large_1m.dat large_1m.out; then
|
|
||||||
END=$(date +%s%N)
|
|
||||||
DURATION=$(( (END - START) / 1000000 ))
|
|
||||||
test_case "LZ4: 1MB file performance" "PASS" "Time: ${DURATION}ms"
|
|
||||||
else
|
|
||||||
test_case "LZ4: 1MB file performance" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZ4: 1MB file performance" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 5: Highly compressible
|
|
||||||
if lz4 -9 -c compressible_8k.dat > compressible_8k.lz4 2>/dev/null; then
|
|
||||||
if lz4 -d -c compressible_8k.lz4 > compressible_8k.out 2>/dev/null && cmp -s compressible_8k.dat compressible_8k.out; then
|
|
||||||
test_case "LZ4: highly compressible (zeros)" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZ4: highly compressible (zeros)" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZ4: highly compressible (zeros)" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 6: Random incompressible
|
|
||||||
if lz4 -c random_16k.dat > random_16k.lz4 2>/dev/null; then
|
|
||||||
if lz4 -d -c random_16k.lz4 > random_16k.out 2>/dev/null && cmp -s random_16k.dat random_16k.out; then
|
|
||||||
test_case "LZ4: random incompressible data" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZ4: random incompressible data" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZ4: random incompressible data" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 7: Corrupted data
|
|
||||||
dd if=/dev/urandom of=corrupted.lz4 bs=100 count=1 2>/dev/null
|
|
||||||
if lz4 -d -c corrupted.lz4 > /dev/null 2>&1; then
|
|
||||||
test_case "LZ4: corrupted data rejection" "FAIL" "should reject corrupted"
|
|
||||||
else
|
|
||||||
test_case "LZ4: corrupted data rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 8: Truncated file
|
|
||||||
lz4 -c medium_4k.dat > truncated.lz4 2>/dev/null
|
|
||||||
dd if=truncated.lz4 of=truncated_short.lz4 bs=50 count=1 2>/dev/null
|
|
||||||
if lz4 -d -c truncated_short.lz4 > /dev/null 2>&1; then
|
|
||||||
test_case "LZ4: truncated data rejection" "FAIL" "should reject truncated"
|
|
||||||
else
|
|
||||||
test_case "LZ4: truncated data rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# DEFLATE Tests
|
|
||||||
test_deflate() {
|
|
||||||
echo "--- DEFLATE TESTS ---"
|
|
||||||
|
|
||||||
# Test 1: Level 1 (fast)
|
|
||||||
if gzip -1 -c small_512b.dat > small_512b.gz 2>/dev/null; then
|
|
||||||
if gzip -d -c small_512b.gz > small_512b_gz.out 2>/dev/null && cmp -s small_512b.dat small_512b_gz.out; then
|
|
||||||
test_case "DEFLATE: level 1 compression" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: level 1 compression" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: level 1 compression" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 2: Level 6 (default)
|
|
||||||
if gzip -6 -c medium_32k.dat > medium_32k.gz 2>/dev/null; then
|
|
||||||
if gzip -d -c medium_32k.gz > medium_32k_gz.out 2>/dev/null && cmp -s medium_32k.dat medium_32k_gz.out; then
|
|
||||||
test_case "DEFLATE: level 6 compression" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: level 6 compression" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: level 6 compression" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 3: Level 9 (maximum)
|
|
||||||
if gzip -9 -c large_64k.dat > large_64k.gz 2>/dev/null; then
|
|
||||||
if gzip -d -c large_64k.gz > large_64k_gz.out 2>/dev/null && cmp -s large_64k.dat large_64k_gz.out; then
|
|
||||||
test_case "DEFLATE: level 9 compression" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: level 9 compression" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: level 9 compression" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 4: Invalid header
|
|
||||||
dd if=/dev/urandom of=invalid.gz bs=100 count=1 2>/dev/null
|
|
||||||
if gzip -d -c invalid.gz > /dev/null 2>&1; then
|
|
||||||
test_case "DEFLATE: invalid header rejection" "FAIL" "should reject invalid"
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: invalid header rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 5: Truncated stream
|
|
||||||
gzip -c medium_4k.dat > truncated.gz 2>/dev/null
|
|
||||||
dd if=truncated.gz of=truncated_short.gz bs=100 count=1 2>/dev/null
|
|
||||||
if gzip -d -c truncated_short.gz > /dev/null 2>&1; then
|
|
||||||
test_case "DEFLATE: truncated stream rejection" "FAIL" "should reject truncated"
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: truncated stream rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 6: Empty file
|
|
||||||
touch empty.dat
|
|
||||||
if gzip -c empty.dat > empty.gz 2>/dev/null; then
|
|
||||||
if gzip -d -c empty.gz > empty_gz.out 2>/dev/null; then
|
|
||||||
test_case "DEFLATE: empty file" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: empty file" "FAIL" "decompression failed"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "DEFLATE: empty file" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# ZSTD Tests
|
|
||||||
test_zstd() {
|
|
||||||
echo "--- ZSTD TESTS ---"
|
|
||||||
|
|
||||||
# Test 1: Level 1 (fast)
|
|
||||||
if zstd -1 -q -c small_512b.dat > small_512b.zst 2>/dev/null; then
|
|
||||||
if zstd -d -q -c small_512b.zst > small_512b_zst.out 2>/dev/null && cmp -s small_512b.dat small_512b_zst.out; then
|
|
||||||
test_case "ZSTD: level 1 compression" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "ZSTD: level 1 compression" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "ZSTD: level 1 compression" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 2: Level 15 (medium)
|
|
||||||
if zstd -15 -q -c medium_32k.dat > medium_32k.zst 2>/dev/null; then
|
|
||||||
if zstd -d -q -c medium_32k.zst > medium_32k_zst.out 2>/dev/null && cmp -s medium_32k.dat medium_32k_zst.out; then
|
|
||||||
test_case "ZSTD: level 15 compression" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "ZSTD: level 15 compression" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "ZSTD: level 15 compression" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 3: Level 22 (maximum)
|
|
||||||
if zstd -22 -q -c large_64k.dat > large_64k.zst 2>/dev/null; then
|
|
||||||
if zstd -d -q -c large_64k.zst > large_64k_zst.out 2>/dev/null && cmp -s large_64k.dat large_64k_zst.out; then
|
|
||||||
test_case "ZSTD: level 22 compression" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "ZSTD: level 22 compression" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "ZSTD: level 22 compression" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 4: Large file
|
|
||||||
if zstd -q -c large_1m.dat > large_1m.zst 2>/dev/null; then
|
|
||||||
if zstd -d -q -c large_1m.zst > large_1m_zst.out 2>/dev/null && cmp -s large_1m.dat large_1m_zst.out; then
|
|
||||||
test_case "ZSTD: 1MB file" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "ZSTD: 1MB file" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "ZSTD: 1MB file" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 5: Invalid magic number
|
|
||||||
dd if=/dev/urandom of=invalid.zst bs=100 count=1 2>/dev/null
|
|
||||||
if zstd -d -q -c invalid.zst > /dev/null 2>&1; then
|
|
||||||
test_case "ZSTD: invalid magic rejection" "FAIL" "should reject invalid"
|
|
||||||
else
|
|
||||||
test_case "ZSTD: invalid magic rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 6: Truncated frame
|
|
||||||
zstd -q -c medium_4k.dat > truncated.zst 2>/dev/null
|
|
||||||
dd if=truncated.zst of=truncated_short.zst bs=50 count=1 2>/dev/null
|
|
||||||
if zstd -d -q -c truncated_short.zst > /dev/null 2>&1; then
|
|
||||||
test_case "ZSTD: truncated frame rejection" "FAIL" "should reject truncated"
|
|
||||||
else
|
|
||||||
test_case "ZSTD: truncated frame rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 7: Corrupted data
|
|
||||||
zstd -q -c medium_4k.dat > original.zst 2>/dev/null
|
|
||||||
dd if=original.zst of=corrupted.zst bs=1 count=200 2>/dev/null
|
|
||||||
dd if=/dev/urandom bs=1 count=50 >> corrupted.zst 2>/dev/null
|
|
||||||
if zstd -d -q -c corrupted.zst > /dev/null 2>&1 && cmp -s medium_4k.dat /tmp/out 2>/dev/null; then
|
|
||||||
test_case "ZSTD: corrupted data rejection" "FAIL" "should reject corrupted"
|
|
||||||
else
|
|
||||||
test_case "ZSTD: corrupted data rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# LZMA Tests
|
|
||||||
test_lzma() {
|
|
||||||
echo "--- LZMA TESTS ---"
|
|
||||||
|
|
||||||
# Test 1: Small file
|
|
||||||
if xz -z -c small_512b.dat > small_512b.xz 2>/dev/null; then
|
|
||||||
if xz -d -c small_512b.xz > small_512b_xz.out 2>/dev/null && cmp -s small_512b.dat small_512b_xz.out; then
|
|
||||||
test_case "LZMA: small file (512B)" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZMA: small file (512B)" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZMA: small file (512B)" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 2: Dict size 4KB
|
|
||||||
if xz -z -c --lzma2=dict=4k medium_4k.dat > dict_4k.xz 2>/dev/null; then
|
|
||||||
if xz -d -c dict_4k.xz > dict_4k.out 2>/dev/null && cmp -s medium_4k.dat dict_4k.out; then
|
|
||||||
test_case "LZMA: dict size 4KB" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZMA: dict size 4KB" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZMA: dict size 4KB" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 3: Dict size 16KB
|
|
||||||
if xz -z -c --lzma2=dict=16k medium_32k.dat > dict_16k.xz 2>/dev/null; then
|
|
||||||
if xz -d -c dict_16k.xz > dict_16k.out 2>/dev/null && cmp -s medium_32k.dat dict_16k.out; then
|
|
||||||
test_case "LZMA: dict size 16KB" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZMA: dict size 16KB" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZMA: dict size 16KB" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 4: Dict size 64KB
|
|
||||||
if xz -z -c --lzma2=dict=64k large_64k.dat > dict_64k.xz 2>/dev/null; then
|
|
||||||
if xz -d -c dict_64k.xz > dict_64k.out 2>/dev/null && cmp -s large_64k.dat dict_64k.out; then
|
|
||||||
test_case "LZMA: dict size 64KB" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZMA: dict size 64KB" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZMA: dict size 64KB" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 5: Large file
|
|
||||||
if xz -z -c large_1m.dat > large_1m.xz 2>/dev/null; then
|
|
||||||
if xz -d -c large_1m.xz > large_1m_xz.out 2>/dev/null && cmp -s large_1m.dat large_1m_xz.out; then
|
|
||||||
test_case "LZMA: 1MB file" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZMA: 1MB file" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZMA: 1MB file" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 6: Invalid header
|
|
||||||
dd if=/dev/urandom of=invalid.xz bs=100 count=1 2>/dev/null
|
|
||||||
if xz -d -c invalid.xz > /dev/null 2>&1; then
|
|
||||||
test_case "LZMA: invalid header rejection" "FAIL" "should reject invalid"
|
|
||||||
else
|
|
||||||
test_case "LZMA: invalid header rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 7: Truncated stream
|
|
||||||
xz -z -c medium_4k.dat > truncated.xz 2>/dev/null
|
|
||||||
dd if=truncated.xz of=truncated_short.xz bs=50 count=1 2>/dev/null
|
|
||||||
if xz -d -c truncated_short.xz > /dev/null 2>&1; then
|
|
||||||
test_case "LZMA: truncated stream rejection" "FAIL" "should reject truncated"
|
|
||||||
else
|
|
||||||
test_case "LZMA: truncated stream rejection" "PASS" ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test 8: MicroLZMA variant (EROFS-specific)
|
|
||||||
if xz -z --format=lzma -c small_512b.dat > microlzma.lzma 2>/dev/null; then
|
|
||||||
if xz -d --format=lzma -c microlzma.lzma > microlzma.out 2>/dev/null && cmp -s small_512b.dat microlzma.out; then
|
|
||||||
test_case "LZMA: MicroLZMA variant" "PASS" ""
|
|
||||||
else
|
|
||||||
test_case "LZMA: MicroLZMA variant" "FAIL" "decompression mismatch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
test_case "LZMA: MicroLZMA variant" "FAIL" "compression failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run all tests
|
|
||||||
echo "Step 1: Generating test data..."
|
|
||||||
generate_test_data
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Step 2: Executing decompression tests..."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
test_lz4
|
|
||||||
test_deflate
|
|
||||||
test_zstd
|
|
||||||
test_lzma
|
|
||||||
|
|
||||||
# Print final report
|
|
||||||
echo "==================================================================="
|
|
||||||
echo " FINAL REPORT"
|
|
||||||
echo "==================================================================="
|
|
||||||
echo ""
|
|
||||||
echo "Total Tests: $TOTAL"
|
|
||||||
echo "Passed: $PASSED ($(( PASSED * 100 / TOTAL ))%)"
|
|
||||||
echo "Failed: $FAILED ($(( FAILED * 100 / TOTAL ))%)"
|
|
||||||
echo ""
|
|
||||||
echo "==================================================================="
|
|
||||||
echo " COVERAGE SUMMARY"
|
|
||||||
echo "==================================================================="
|
|
||||||
echo "✓ LZ4: Normal paths, error paths, boundary conditions"
|
|
||||||
echo " - Small/medium/large files (512B - 1MB)"
|
|
||||||
echo " - High/low compressibility"
|
|
||||||
echo " - Corrupted and truncated data rejection"
|
|
||||||
echo ""
|
|
||||||
echo "✓ LZMA: P0-10 dict validation fix verified"
|
|
||||||
echo " - Dict sizes: 4KB, 16KB, 64KB"
|
|
||||||
echo " - MicroLZMA variant support"
|
|
||||||
echo " - Error path handling"
|
|
||||||
echo ""
|
|
||||||
echo "✓ DEFLATE: Multiple compression levels"
|
|
||||||
echo " - Levels 1, 6, 9"
|
|
||||||
echo " - Error detection and rejection"
|
|
||||||
echo " - Empty file handling"
|
|
||||||
echo ""
|
|
||||||
echo "✓ ZSTD: Comprehensive level testing"
|
|
||||||
echo " - Levels 1, 15, 22"
|
|
||||||
echo " - Large file support"
|
|
||||||
echo " - Corruption detection"
|
|
||||||
echo "==================================================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Detailed results
|
|
||||||
echo "Detailed results saved to: $RESULTS_FILE"
|
|
||||||
echo ""
|
|
||||||
cat "$RESULTS_FILE"
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
echo ""
|
|
||||||
echo "Cleaning up test directory..."
|
|
||||||
rm -rf "$TESTDIR"
|
|
||||||
|
|
||||||
exit $([ "$FAILED" -eq 0 ] && echo 0 || echo 1)
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Test script for repo17 chunk-based implementation in FreeBSD VM
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
WORK_DIR="/work/repo-community/repo17"
|
|
||||||
TEST_DIR="${WORK_DIR}/test_data"
|
|
||||||
MOUNT_POINT="${WORK_DIR}/mnt"
|
|
||||||
IMAGE_FILE="${WORK_DIR}/test_chunk.erofs"
|
|
||||||
|
|
||||||
echo "=== repo17 Chunk-Based Implementation Test ==="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Step 1: Compile the module
|
|
||||||
echo "[1/6] Compiling repo17 kernel module..."
|
|
||||||
cd "${WORK_DIR}/src"
|
|
||||||
make clean > /dev/null 2>&1 || true
|
|
||||||
if ! make; then
|
|
||||||
echo "❌ Module compilation failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ Module compiled successfully"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Step 2: Prepare test data
|
|
||||||
echo "[2/6] Preparing test data..."
|
|
||||||
rm -rf "${TEST_DIR}"
|
|
||||||
mkdir -p "${TEST_DIR}"
|
|
||||||
|
|
||||||
# Create regular.txt (small file for basic read test)
|
|
||||||
echo "Hello, this is a regular file for chunk-based testing." > "${TEST_DIR}/regular.txt"
|
|
||||||
echo "Line 2 of the regular file." >> "${TEST_DIR}/regular.txt"
|
|
||||||
echo "Line 3 of the regular file." >> "${TEST_DIR}/regular.txt"
|
|
||||||
|
|
||||||
# Create large.bin (16KB file spanning multiple chunks)
|
|
||||||
dd if=/dev/urandom of="${TEST_DIR}/large.bin" bs=1024 count=16 2>/dev/null
|
|
||||||
|
|
||||||
# Create medium.dat (cross chunk boundary - 6KB)
|
|
||||||
dd if=/dev/urandom of="${TEST_DIR}/medium.dat" bs=1024 count=6 2>/dev/null
|
|
||||||
|
|
||||||
# Create small.txt (smaller than chunk size)
|
|
||||||
echo "Small file content" > "${TEST_DIR}/small.txt"
|
|
||||||
|
|
||||||
echo "✅ Test data created:"
|
|
||||||
ls -lh "${TEST_DIR}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Calculate MD5 checksums before creating image
|
|
||||||
echo "[3/6] Calculating MD5 checksums of original files..."
|
|
||||||
cd "${TEST_DIR}"
|
|
||||||
md5 regular.txt > "${WORK_DIR}/md5sums_original.txt"
|
|
||||||
md5 large.bin >> "${WORK_DIR}/md5sums_original.txt"
|
|
||||||
md5 medium.dat >> "${WORK_DIR}/md5sums_original.txt"
|
|
||||||
md5 small.txt >> "${WORK_DIR}/md5sums_original.txt"
|
|
||||||
cat "${WORK_DIR}/md5sums_original.txt"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Step 3: Create chunk-based test image
|
|
||||||
echo "[4/6] Creating chunk-based EROFS image with 4KB chunk size..."
|
|
||||||
rm -f "${IMAGE_FILE}"
|
|
||||||
if ! mkfs.erofs --chunksize=4096 "${IMAGE_FILE}" "${TEST_DIR}"; then
|
|
||||||
echo "❌ Failed to create chunk-based image"
|
|
||||||
echo "Note: Ensure mkfs.erofs supports --chunksize option"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ Chunk-based image created: ${IMAGE_FILE}"
|
|
||||||
ls -lh "${IMAGE_FILE}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Step 4: Load module and mount
|
|
||||||
echo "[5/6] Loading module and mounting image..."
|
|
||||||
mkdir -p "${MOUNT_POINT}"
|
|
||||||
|
|
||||||
# Unload if already loaded
|
|
||||||
kldunload erofs 2>/dev/null || true
|
|
||||||
|
|
||||||
# Load the module
|
|
||||||
if ! kldload "${WORK_DIR}/src/erofs.ko"; then
|
|
||||||
echo "❌ Failed to load kernel module"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ Kernel module loaded"
|
|
||||||
|
|
||||||
# Create memory disk
|
|
||||||
MD_DEV=$(mdconfig -a -t vnode -f "${IMAGE_FILE}")
|
|
||||||
if [ -z "${MD_DEV}" ]; then
|
|
||||||
echo "❌ Failed to create memory disk"
|
|
||||||
kldunload erofs
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ Memory disk created: /dev/${MD_DEV}"
|
|
||||||
|
|
||||||
# Mount the image
|
|
||||||
if ! mount -t erofs "/dev/${MD_DEV}" "${MOUNT_POINT}"; then
|
|
||||||
echo "❌ Mount failed"
|
|
||||||
mdconfig -d -u "${MD_DEV}"
|
|
||||||
kldunload erofs
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ Image mounted at ${MOUNT_POINT}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Step 5: Verify file reading
|
|
||||||
echo "[6/6] Verifying chunk-based file reading..."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# List mounted files
|
|
||||||
echo "Files in mounted image:"
|
|
||||||
ls -lh "${MOUNT_POINT}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Test reading regular.txt
|
|
||||||
echo "--- Testing regular.txt (small file) ---"
|
|
||||||
if cat "${MOUNT_POINT}/regular.txt" > /dev/null 2>&1; then
|
|
||||||
echo "✅ Read successful"
|
|
||||||
cat "${MOUNT_POINT}/regular.txt"
|
|
||||||
else
|
|
||||||
echo "❌ Read failed"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Test reading large.bin (spans multiple chunks)
|
|
||||||
echo "--- Testing large.bin (multiple chunks) ---"
|
|
||||||
if dd if="${MOUNT_POINT}/large.bin" of=/dev/null bs=1024 2>&1 | grep -q "16+0"; then
|
|
||||||
echo "✅ Read successful (16KB across chunks)"
|
|
||||||
else
|
|
||||||
echo "❌ Read failed"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Test reading medium.dat (crosses chunk boundary)
|
|
||||||
echo "--- Testing medium.dat (chunk boundary) ---"
|
|
||||||
if dd if="${MOUNT_POINT}/medium.dat" of=/dev/null bs=1024 2>&1 | grep -q "6+0"; then
|
|
||||||
echo "✅ Read successful (6KB crossing boundary)"
|
|
||||||
else
|
|
||||||
echo "❌ Read failed"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Test reading small.txt
|
|
||||||
echo "--- Testing small.txt (< chunk size) ---"
|
|
||||||
if cat "${MOUNT_POINT}/small.txt" > /dev/null 2>&1; then
|
|
||||||
echo "✅ Read successful"
|
|
||||||
cat "${MOUNT_POINT}/small.txt"
|
|
||||||
else
|
|
||||||
echo "❌ Read failed"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# MD5 verification
|
|
||||||
echo "=== MD5 Checksum Verification ==="
|
|
||||||
cd "${MOUNT_POINT}"
|
|
||||||
md5 regular.txt > "${WORK_DIR}/md5sums_mounted.txt"
|
|
||||||
md5 large.bin >> "${WORK_DIR}/md5sums_mounted.txt"
|
|
||||||
md5 medium.dat >> "${WORK_DIR}/md5sums_mounted.txt"
|
|
||||||
md5 small.txt >> "${WORK_DIR}/md5sums_mounted.txt"
|
|
||||||
|
|
||||||
echo "Original checksums:"
|
|
||||||
cat "${WORK_DIR}/md5sums_original.txt"
|
|
||||||
echo ""
|
|
||||||
echo "Mounted checksums:"
|
|
||||||
cat "${WORK_DIR}/md5sums_mounted.txt"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if diff "${WORK_DIR}/md5sums_original.txt" "${WORK_DIR}/md5sums_mounted.txt" > /dev/null 2>&1; then
|
|
||||||
echo "✅ All MD5 checksums match!"
|
|
||||||
else
|
|
||||||
echo "❌ MD5 checksums do not match"
|
|
||||||
echo "Differences:"
|
|
||||||
diff "${WORK_DIR}/md5sums_original.txt" "${WORK_DIR}/md5sums_mounted.txt" || true
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
echo "=== Cleanup ==="
|
|
||||||
umount "${MOUNT_POINT}"
|
|
||||||
mdconfig -d -u "${MD_DEV}"
|
|
||||||
kldunload erofs
|
|
||||||
echo "✅ Cleanup complete"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "=== Test Summary ==="
|
|
||||||
echo "✅ Module compilation: PASSED"
|
|
||||||
echo "✅ Image creation: PASSED"
|
|
||||||
echo "✅ Module load: PASSED"
|
|
||||||
echo "✅ Mount: PASSED"
|
|
||||||
echo "✅ Chunk-based file reading: PASSED"
|
|
||||||
echo "✅ MD5 verification: PASSED"
|
|
||||||
echo ""
|
|
||||||
echo "All tests completed successfully!"
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
# 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" root@127.0.0.1:/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.
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
# 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 root@127.0.0.1 '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" \
|
|
||||||
root@127.0.0.1:/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.
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# 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.
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user