test code v1
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,283 @@
|
||||
# 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 控制面
|
||||
@@ -0,0 +1,65 @@
|
||||
# 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
@@ -0,0 +1,271 @@
|
||||
.\" 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
|
||||
@@ -0,0 +1,77 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,65 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,83 @@
|
||||
# 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`.
|
||||
@@ -0,0 +1,84 @@
|
||||
# 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).
|
||||
@@ -0,0 +1,80 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,268 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,99 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,86 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,314 @@
|
||||
# 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`
|
||||
@@ -0,0 +1,74 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,191 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,132 @@
|
||||
# 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`.
|
||||
@@ -0,0 +1,158 @@
|
||||
# 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`.
|
||||
@@ -0,0 +1,142 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,62 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,26 @@
|
||||
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.
|
||||
@@ -0,0 +1,16 @@
|
||||
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.
|
||||
@@ -0,0 +1,21 @@
|
||||
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.
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
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.
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"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}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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 一致。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 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;测试后无遗留挂载或模块。
|
||||
Reference in New Issue
Block a user