update
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 - 压缩配置解析和统一调度
|
||||
├── decompressor_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 - 扩展属性接口
|
||||
```
|
||||
|
||||
## 分层架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 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 保留独立 `decompressor_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`、
|
||||
`tests/test_decompress.c` 和 `tests/test_decompress_standalone.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,36 @@
|
||||
# Pre10 Baseline
|
||||
|
||||
Pre10 was created as an exact tracked-tree snapshot of `repo-pre-9` before
|
||||
any Pre10 planning or source changes.
|
||||
|
||||
## Source identity
|
||||
|
||||
- Repository HEAD: `bedc8dae477ba0e82a4a7c4f0de7ccdd41696004`
|
||||
- `repo-pre-9` tree: `54b2845b80c33f05109af1fea84e962aca3a82d3`
|
||||
- `repo-pre-9/src` tree: `e657e8a63b097b061670f75ca01947a568ef33d5`
|
||||
|
||||
## Copy verification
|
||||
|
||||
Before this baseline file was added, `repo-pre-10` matched `repo-pre-9` in:
|
||||
|
||||
- file and directory manifest;
|
||||
- byte-for-byte file contents;
|
||||
- file modes and timestamps;
|
||||
- complete subtree tree hash;
|
||||
- `src` subtree tree hash.
|
||||
|
||||
The copied tree contained no nested `.git` directory, image, binary build
|
||||
artifact, temporary file, or file larger than 10 MiB.
|
||||
|
||||
## Pre9 validation reference
|
||||
|
||||
The final Pre9 manual QEMU smoke validation is recorded in
|
||||
[`pre9-cache-final-manual-validation.md`](pre9-cache-final-manual-validation.md).
|
||||
It reports successful KLD build/load and read-only mounts, correct LZMA
|
||||
single-read and full-file hashes, successful concurrent LZMA reads, a passing
|
||||
LZ4 regression read, and complete test resource cleanup.
|
||||
|
||||
## Pre10 state
|
||||
|
||||
No Pre10 source, build, configuration, or planning change has been made. This
|
||||
file only records the snapshot baseline.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Pre10 Batch A: Compatibility Cleanup and Ordering
|
||||
|
||||
## Scope and baseline
|
||||
|
||||
Batch A changes only `src/internal.h`, `src/data.c`, and `src/zmap.c`. It is a
|
||||
source-only structural change based on commit
|
||||
`b5d6f5ce0696407f9f1cb3f0a9f8cbab643eea49`. No QEMU or feature test was run.
|
||||
|
||||
The starting blobs were:
|
||||
|
||||
| Path | Blob |
|
||||
| --- | --- |
|
||||
| `src/internal.h` | `cfa15de12b73319322ebb33049a7f14b9eb5c271` |
|
||||
| `src/data.c` | `fdc138b0dad12501d842bae124c8c020793dbc97` |
|
||||
| `src/zmap.c` | `51170741a0fb5eced814db898c1a233e8a23088a` |
|
||||
|
||||
## Removed compatibility declarations
|
||||
|
||||
Repository-wide fixed-string searches covered all files below
|
||||
`repo-pre-10`, including source, the Makefile, and documentation. The only
|
||||
non-definition match was an old review report describing
|
||||
`erofs_is_fileio_mode()` as dead code.
|
||||
|
||||
| Candidate | Source consumers | Result |
|
||||
| --- | ---: | --- |
|
||||
| `EROFS_SYNC_DECOMPRESS_AUTO` and related enum values | 0 | Removed |
|
||||
| `EROFS_ZIP_CACHE_DISABLED` and related enum values | 0 | Removed |
|
||||
| `struct erofs_buf` | 0 | Removed |
|
||||
| `__EROFS_BUF_INITIALIZER` | 0 | Removed |
|
||||
| `erofs_map_blocks.buf` | 0 | Removed with its dead type |
|
||||
| `erofs_is_fileio_mode()` | 0 | Removed |
|
||||
|
||||
These declarations modeled Linux facilities that the synchronous contiguous-
|
||||
buffer FreeBSD path does not implement. Their removal does not replace or
|
||||
alter the mount-owned decoded LZMA extent cache introduced in Pre9.
|
||||
|
||||
## Declaration and definition order
|
||||
|
||||
`internal.h` now exposes explicit groups for buffer/device I/O, inode/vnode
|
||||
lifecycle, directory operations, logical mapping/file data, compressed
|
||||
mapping/data, compression configuration/backends, and VOP vectors. Existing
|
||||
signatures are unchanged.
|
||||
|
||||
In `data.c`, the regular-file wrapper now precedes the symlink wrapper, matching
|
||||
the header's file-data grouping. Both wrappers retain their original bodies
|
||||
and continue to delegate to `erofs_read_uio()`.
|
||||
|
||||
In `zmap.c`, `z_erofs_read_extent()` now follows the overflow-safe extent
|
||||
position helpers it consumes. The Linux-shared compressed-index and map
|
||||
functions retain their existing relative order; FreeBSD-only explicit-extent
|
||||
helpers remain one contiguous responsibility group.
|
||||
|
||||
The reordering was deliberately bounded by the existing static call topology:
|
||||
|
||||
- `erofs_check_device_range()` remains before `erofs_map_dev()`;
|
||||
- `erofs_inline_tail_start()` and `erofs_map_blocks_chunk()` remain before
|
||||
`erofs_map_blocks()`;
|
||||
- `erofs_bread_device()` remains before `erofs_bread()` and
|
||||
`erofs_read_physical()`;
|
||||
- `erofs_read_uio()` remains before both public vnode read wrappers;
|
||||
- compressed-index decode/load helpers remain before their callers;
|
||||
- `z_erofs_map_blocks_fo()` and `z_erofs_validate_extent_table()` remain
|
||||
before `z_erofs_fill_inode()`; and
|
||||
- fill, full/explicit mapping, and sanity helpers remain before
|
||||
`z_erofs_map_blocks_iter()`.
|
||||
|
||||
No extra static prototype was introduced. Broader movement of
|
||||
`erofs_map_dev()` was rejected in this batch because matching Linux's exact
|
||||
position would either violate the current dependency order or add a prototype
|
||||
solely to support cosmetic movement.
|
||||
|
||||
## Preserved behavior
|
||||
|
||||
- No function signature, return value, allocation flag, lock operation,
|
||||
`bread`/`brelse` ownership, mapping flag, or control-flow statement changed.
|
||||
- No structure field used by runtime code moved or changed.
|
||||
- The Pre9 decoded extent cache fields, initialization/finalization calls,
|
||||
key, lock, and one-entry-per-mount policy are untouched.
|
||||
- No Linux page, folio, bio, workqueue, XArray, shrinker, or compatibility
|
||||
wrapper was introduced.
|
||||
|
||||
## Static validation
|
||||
|
||||
| Check | Result | Evidence |
|
||||
| --- | --- | --- |
|
||||
| Removed-symbol search | PASS | Every removed enum, type, initializer, helper, and `map_blocks.buf` access has zero source/Makefile matches. |
|
||||
| Prototype uniqueness | PASS | Each of the 25 grouped cross-file declarations occurs exactly once in `internal.h`. |
|
||||
| `erofs_read_file()` body | PASS | Parent and working-tree normalized hashes are both `acc4cb05f9a1eb4a0066f8e4d6f3e84c8a69cfb70c762233a61ab08e84836aef`. |
|
||||
| `erofs_readlink_target()` body | PASS | Parent and working-tree normalized hashes are both `73cc37f21f0c66a2c6bb27d39cc9f93f38df1994c7d386dacb5efc7734aa6a89`. |
|
||||
| `z_erofs_read_extent()` body | PASS | Parent and working-tree normalized hashes are both `9145b1220329a2d113c69971c94537a99467a7252f3ea564b695a4530ea8e11d`. |
|
||||
| Changed-path allowlist | PASS | Only the three source files and this Batch A report changed. |
|
||||
| `git diff --check` | PASS | No whitespace errors. |
|
||||
| QEMU/build | NOT RUN | Reserved for final aggregate Pre10 validation. |
|
||||
|
||||
The final Pre10 guest build and smoke run are intentionally deferred to the
|
||||
aggregate validation stage defined by `planning/pre10/validation.md`.
|
||||
@@ -0,0 +1,108 @@
|
||||
# Pre10 Batch B: Bounded Metadata Helpers
|
||||
|
||||
## Scope and baseline
|
||||
|
||||
Batch B is a source-only extraction based on commit
|
||||
`3c7c774b296a2ee90578a78f372aad5fd2edbec6`. It changes only
|
||||
`src/super.c`, `src/data.c`, and `src/inode.c`, plus this report. No build,
|
||||
QEMU smoke, or feature test was run.
|
||||
|
||||
The extraction keeps ownership at the original FreeBSD lifecycle boundaries:
|
||||
|
||||
- `erofs_mountfs()` still owns mount allocation, the primary GEOM transfer,
|
||||
extent-cache lifecycle, device scanning, internal inode setup, publication,
|
||||
and the single `erofs_sb_free()` failure path.
|
||||
- `erofs_map_dev()` still owns device selection, range and overflow checks,
|
||||
flat-device behavior, and all `ENODEV`/`EINTEGRITY` returns.
|
||||
- `erofs_vget()` still owns vnode allocation, locking, mount association,
|
||||
hash insertion, construction state, publication, and failure cleanup.
|
||||
|
||||
## Superblock helper
|
||||
|
||||
`erofs_read_superblock()` now reads the on-disk superblock into a temporary
|
||||
buffer, copies the fixed 144-byte structure to caller-owned stack storage,
|
||||
releases the temporary buffer, and performs the existing validation and field
|
||||
decode in the original order. It also retains the existing device-size,
|
||||
checksum, generation-seed, metabox-NID, and compression-configuration checks.
|
||||
|
||||
The helper does not allocate or publish the mount, open extra devices, create
|
||||
internal inodes, initialize xattrs, or own failure cleanup. `erofs_mountfs()`
|
||||
still calls, in order:
|
||||
|
||||
```text
|
||||
z_erofs_extent_cache_init
|
||||
erofs_read_superblock
|
||||
erofs_scan_devices
|
||||
shared-EA/metabox combination check
|
||||
erofs_init_packed_inode
|
||||
erofs_init_metabox_inode
|
||||
erofs_xattr_prefixes_init
|
||||
mount publication and flag setup
|
||||
```
|
||||
|
||||
All prior superblock outcomes remain at the same semantic boundary:
|
||||
|
||||
| Condition | Preserved result |
|
||||
| --- | --- |
|
||||
| read failure | underlying `erofs_bread()` error |
|
||||
| invalid magic or block geometry | `EINVAL` |
|
||||
| unsupported directory blocks or feature bits | `EOPNOTSUPP` |
|
||||
| invalid xattr, timestamp, or metabox metadata | `EINTEGRITY` |
|
||||
| invalid device geometry | existing `EINVAL`, `EINTEGRITY`, or `ENXIO` |
|
||||
| checksum mismatch | `EINTEGRITY` |
|
||||
| generation/config read failure | existing underlying error |
|
||||
|
||||
Copying the superblock before releasing its read buffer makes its lifetime
|
||||
explicit. The copy remains available to `erofs_scan_devices()` and volume-name
|
||||
publication, while checksum and compression configuration reads continue to
|
||||
use their existing independent I/O helpers.
|
||||
|
||||
## Device-map helper
|
||||
|
||||
`erofs_fill_map_dev()` is a pure assignment helper for `m_em`, `m_dif`, and
|
||||
`m_pa`. It has no branches, errors, allocation, I/O, or ownership effects.
|
||||
|
||||
The caller retains all explicit-device and unified-range selection, arithmetic
|
||||
overflow checks, physical range validation, flat-device handling, and external
|
||||
device availability checks. In particular:
|
||||
|
||||
- flat explicit mappings still use the primary device and add the unified
|
||||
offset to the existing physical address;
|
||||
- flat implicit mappings still retain the primary device and unified address;
|
||||
- non-flat explicit mappings select the requested extra device only after all
|
||||
validation succeeds; and
|
||||
- non-flat implicit misses still return success with the initial primary map.
|
||||
|
||||
## Vnode helper
|
||||
|
||||
`erofs_fill_vnode()` sets only the inode-derived vnode type, FIFO operation
|
||||
vector, and `VV_ROOT` flag. It runs after `erofs_read_inode()` succeeds and
|
||||
immediately before `VSTATE_CONSTRUCTED`, while `erofs_vget()` still holds the
|
||||
exclusive vnode lock.
|
||||
|
||||
Hash lookup/insertion, allocation, `insmntque()`, locking, race handling,
|
||||
failure `vgone()`/`vput()`, shared-lock downgrade, and `*vpp` publication remain
|
||||
in `erofs_vget()` in their original order.
|
||||
|
||||
## Known pre-existing risk
|
||||
|
||||
The `insmntque()` failure branch remains unchanged. FreeBSD's `insmntque()` may
|
||||
reclaim and release the vnode on failure, while the existing EROFS branch then
|
||||
accesses `vp->v_data`. This possible use-after-release is outside a helper-only
|
||||
batch and was deliberately not mixed into this commit. Consequently, this
|
||||
report does not claim that the pre-existing vnode cleanup path is correct.
|
||||
|
||||
## Static validation
|
||||
|
||||
| Check | Result | Evidence |
|
||||
| --- | --- | --- |
|
||||
| Changed-path allowlist | PASS | Only three allowed source files and this report changed. |
|
||||
| Helper ownership | PASS | Each helper is `static` and has one direct caller. |
|
||||
| Mount lifecycle order | PASS | Cache init, device scan, internal inode/xattr setup, publication, and `erofs_sb_free()` remain in `erofs_mountfs()`. |
|
||||
| Device-map errors | PASS | All range, overflow, device-selection, `ENODEV`, and `EINTEGRITY` branches remain in `erofs_map_dev()`. |
|
||||
| Vnode lifecycle order | PASS | `insmntque()`, hash insertion, inode read, construction, downgrade, and publication retain their order. |
|
||||
| `git diff --check` | PASS | No whitespace errors. |
|
||||
| Build/QEMU/feature test | NOT RUN | Reserved for later aggregate Pre10 validation. |
|
||||
|
||||
The pre-existing `insmntque()` concern is deferred; no new errno, logging,
|
||||
ABI, Linux lifecycle facade, or Pre9 decoded-cache change was introduced.
|
||||
@@ -0,0 +1,216 @@
|
||||
# Pre10 Batch C: BSD Decompressor Request Dispatch
|
||||
|
||||
Status: **STATIC PASS; RUNTIME NOT RUN**
|
||||
|
||||
This batch aligns the BSD decompressor boundary with the Linux source shape
|
||||
where the responsibility is equivalent. It keeps the FreeBSD implementation
|
||||
synchronous and contiguous-buffer based. No page, folio, bio, workqueue,
|
||||
XArray, shrinker, or asynchronous decompression abstraction was added.
|
||||
|
||||
## Baseline and Scope
|
||||
|
||||
The implementation starts from Pre10 commit `d3c1cb90` and preserves Batch A,
|
||||
Batch B, and the documented `insmntque()` lifecycle issue. The source changes
|
||||
are limited to:
|
||||
|
||||
```text
|
||||
repo-pre-10/src/internal.h
|
||||
repo-pre-10/src/decompressor.c
|
||||
repo-pre-10/src/lz4.c
|
||||
repo-pre-10/src/decompressor_lzma.c
|
||||
repo-pre-10/src/decompressor_deflate.c
|
||||
repo-pre-10/src/decompressor_zstd.c
|
||||
```
|
||||
|
||||
`zdata.c` was inspected but did not need a mechanical edit: its existing call
|
||||
to `z_erofs_decompress()` remains the sole dispatcher call, and its buffer
|
||||
release and decoded LZMA extent-cache publication remain unchanged.
|
||||
|
||||
## Request Contract
|
||||
|
||||
The new request is stack-owned by `z_erofs_decompress()` and is valid only for
|
||||
the synchronous callback invocation:
|
||||
|
||||
```c
|
||||
struct z_erofs_decompress_req {
|
||||
struct erofs_mount *em;
|
||||
const struct erofs_map_blocks *map;
|
||||
const void *in;
|
||||
size_t inputsize;
|
||||
void *out;
|
||||
size_t outputsize;
|
||||
bool partial_decoding;
|
||||
};
|
||||
```
|
||||
|
||||
Field mapping is direct:
|
||||
|
||||
| Request field | Previous source | Ownership |
|
||||
| --- | --- | --- |
|
||||
| `em` | `em` / codec configuration arguments | Borrowed mount, never retained |
|
||||
| `map` | `map` and its algorithm/offset fields | Borrowed mapping, never retained |
|
||||
| `in` | `src` after padding removal | Borrowed compressed buffer |
|
||||
| `inputsize` | `srclen` after padding removal | Value copy |
|
||||
| `out` | `dst` | Borrowed decoded buffer |
|
||||
| `outputsize` | `dstlen` | Value copy |
|
||||
| `partial_decoding` | `partial` | Value copy |
|
||||
|
||||
The request does not own either data buffer. `zdata.c` continues to release
|
||||
the compressed buffer with `erofs_brelse()`, and continues to free or publish
|
||||
the decoded allocation after the callback returns.
|
||||
|
||||
The descriptor callback is intentionally synchronous:
|
||||
|
||||
```c
|
||||
struct z_erofs_decompressor {
|
||||
const char *name;
|
||||
int (*config)(struct erofs_mount *,
|
||||
const struct erofs_super_block *, const void *, size_t);
|
||||
int (*decompress)(const struct z_erofs_decompress_req *);
|
||||
};
|
||||
```
|
||||
|
||||
The configuration callback receives the superblock argument because the LZ4
|
||||
legacy configuration path uses it. The other codec configuration callbacks
|
||||
retain their previous inputs and explicitly ignore that additional argument.
|
||||
|
||||
## Descriptor Coverage
|
||||
|
||||
`decompressor.c` contains one static array indexed by the on-disk algorithm
|
||||
number. The entries are:
|
||||
|
||||
```text
|
||||
0 LZ4 config + z_erofs_lz4_decompress
|
||||
1 LZMA config + z_erofs_lzma_decompress
|
||||
2 DEFLATE config + z_erofs_deflate_decompress
|
||||
3 ZSTD config + z_erofs_zstd_decompress
|
||||
4 SHIFTED plain transform callback
|
||||
5 INTERLACED plain transform callback
|
||||
```
|
||||
|
||||
The first four entries cover every real EROFS compression algorithm currently
|
||||
defined by `erofs_fs.h`. The two runtime-only entries cover the existing plain
|
||||
mapping forms. No duplicate backend entry point or compatibility wrapper is
|
||||
present.
|
||||
|
||||
Configuration parsing preserves the old ordering:
|
||||
|
||||
1. Read the configuration record and its payload.
|
||||
2. Return the read error immediately if either read fails.
|
||||
3. Select the descriptor and invoke its configuration callback.
|
||||
4. Release the payload with `erofs_brelse()`.
|
||||
5. Return the callback's original error unchanged.
|
||||
|
||||
This retains the existing I/O-error priority. Unknown on-disk algorithm bits
|
||||
are rejected before configuration reads by the existing
|
||||
`Z_EROFS_ALL_COMPR_ALGS` mask check. A supported algorithm whose configuration
|
||||
is unavailable returns `EOPNOTSUPP` from its existing callback. In particular,
|
||||
the no-`ZSTDIO` build still emits the existing mount error and returns
|
||||
`EOPNOTSUPP`.
|
||||
|
||||
## Decode and Error Semantics
|
||||
|
||||
The old and new paths have the following equivalent behavior:
|
||||
|
||||
| Condition | Result before Batch C | Result after Batch C |
|
||||
| --- | --- | --- |
|
||||
| Shifted/interlaced output larger than input | `EINTEGRITY` | `EINTEGRITY` |
|
||||
| Shifted/interlaced transform success | `0` | `0` |
|
||||
| Invalid algorithm format | `EOPNOTSUPP` | `EOPNOTSUPP` |
|
||||
| Required zero-padding absent | `EINTEGRITY` | `EINTEGRITY` |
|
||||
| LZMA dictionary not configured | `EINTEGRITY` | `EINTEGRITY` |
|
||||
| Backend success | `0` | `0` |
|
||||
| Any backend failure | `EIO` | `EIO` |
|
||||
|
||||
Padding removal remains in the dispatcher and is performed before the backend
|
||||
request is updated. The LZ4 zero-padding exception remains unchanged. The LZMA
|
||||
dictionary check remains before callback dispatch. Backend-specific checks are
|
||||
unchanged apart from reading their previous parameters from the request or
|
||||
mount configuration:
|
||||
|
||||
- LZ4 preserves literal/match bounds, overlap copying, partial completion,
|
||||
and trailing-zero validation.
|
||||
- MicroLZMA preserves input/output size limits, dictionary selection, decoder
|
||||
shutdown, full-stream consumption, and partial output acceptance.
|
||||
- DEFLATE preserves window validation, `inflateEnd()`, no-progress detection,
|
||||
output completion, and full-stream input consumption.
|
||||
- ZSTD preserves window selection, decoder destruction on every initialized
|
||||
path, no-progress detection, output completion, and full-stream consumption.
|
||||
|
||||
## Consumer and Symbol Proof
|
||||
|
||||
Before the change, repository searches found exactly one in-tree consumer of
|
||||
each old backend symbol: the switch in `decompressor.c`. The only consumer of
|
||||
`z_erofs_decompress()` is `zdata.c`. After the change:
|
||||
|
||||
```text
|
||||
old lz4_decompress 0 definitions/references
|
||||
old lzma_decompress 0 definitions/references
|
||||
old deflate_decompress 0 definitions/references
|
||||
old zstd_decompress 0 definitions/references
|
||||
|
||||
new LZ4 backend one definition, one descriptor reference, one prototype
|
||||
new LZMA backend one definition, one descriptor reference, one prototype
|
||||
new DEFLATE backend one definition, one descriptor reference, one prototype
|
||||
new ZSTD backend two definitions for #ifdef/#else, one descriptor reference,
|
||||
one prototype
|
||||
```
|
||||
|
||||
The two ZSTD definitions are mutually exclusive build branches, not duplicate
|
||||
runtime implementations. No old-name wrapper was retained because no real
|
||||
consumer remains.
|
||||
|
||||
## Cache and Ownership Review
|
||||
|
||||
The Pre9 decoded LZMA cache policy is untouched. The request callback returns
|
||||
before the cache code runs, so the following remain owned by `zdata.c`:
|
||||
|
||||
- compressed-buffer release;
|
||||
- decoded allocation cleanup on failure;
|
||||
- decoded extent publication;
|
||||
- duplicate-cache replacement and old-entry freeing;
|
||||
- one-entry-per-mount bound and cache lock lifecycle.
|
||||
|
||||
No callback stores the request pointer or either borrowed buffer after return.
|
||||
|
||||
## Static Checks
|
||||
|
||||
The following checks were run before this report was written:
|
||||
|
||||
```sh
|
||||
git diff --check
|
||||
git diff --name-only | sort
|
||||
grep -RInE '(^|[^_])(lz4_decompress|lzma_decompress|deflate_decompress|zstd_decompress)\\(' repo-pre-10/src
|
||||
grep -RInE 'z_erofs_(lz4|lzma|deflate|zstd)_decompress' repo-pre-10/src
|
||||
grep -RInE '\\b(page|folio|bio|workqueue|xarray|shrinker)\\b' \\
|
||||
repo-pre-10/src/internal.h repo-pre-10/src/decompressor.c \\
|
||||
repo-pre-10/src/lz4.c repo-pre-10/src/decompressor_lzma.c \\
|
||||
repo-pre-10/src/decompressor_deflate.c repo-pre-10/src/decompressor_zstd.c \\
|
||||
repo-pre-10/src/zdata.c
|
||||
```
|
||||
|
||||
Results:
|
||||
|
||||
- `git diff --check`: PASS.
|
||||
- Changed paths: only the six allowed source files: PASS.
|
||||
- Old backend symbol search: no matches: PASS.
|
||||
- New backend definitions and descriptor references: PASS.
|
||||
- Forbidden Linux memory-model concepts in the changed codec boundary: no
|
||||
matches: PASS.
|
||||
- Descriptor entries: six unique designated entries covering algorithms 0-5:
|
||||
PASS.
|
||||
- `zdata.c` cache and ownership diff: unchanged: PASS.
|
||||
|
||||
The host is not a FreeBSD build environment, so this batch does not claim a
|
||||
KLD build. Per the Pre10 instruction, QEMU smoke testing and the full feature
|
||||
matrix were not run in this batch.
|
||||
|
||||
## Concerns and Deferred Validation
|
||||
|
||||
The primary remaining validation is a FreeBSD guest KLD build followed by the
|
||||
planned Pre10 smoke run. That runtime work is intentionally separate from this
|
||||
static implementation batch. Full feature tests remain outside Pre10.
|
||||
|
||||
The existing `erofs_vget()` `insmntque()` failure-path P1 remains documented
|
||||
in `repo-pre-10/issues/erofs-vget-insmntque-failure-use-after-release.md` and
|
||||
was not changed here.
|
||||
@@ -0,0 +1,347 @@
|
||||
# Pre10 Completion and Targeted Smoke Report
|
||||
|
||||
Status: **PRE10 IMPLEMENTATION COMPLETE; TARGETED SMOKE PASS; FULL FEATURE TEST NOT RUN**
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Scope and goals
|
||||
|
||||
Pre10 is a controlled maintenance-alignment release based on the final Pre9
|
||||
tree. Its purpose is to make the FreeBSD EROFS implementation easier to compare
|
||||
and maintain alongside the independent Linux EROFS repository without copying
|
||||
Linux-only lifecycle or memory-management models.
|
||||
|
||||
The planned work was limited to three source batches:
|
||||
|
||||
1. Remove unused Linux-shaped compatibility declarations and improve source
|
||||
ordering.
|
||||
2. Extract bounded helpers where Linux and FreeBSD responsibilities are
|
||||
comparable, while retaining FreeBSD ownership and errno behavior.
|
||||
3. Introduce a BSD-native synchronous decompressor request and descriptor
|
||||
boundary with Linux-comparable codec names.
|
||||
|
||||
Full feature validation, CI execution, performance redesign, Linux page/folio/
|
||||
bio/workqueue integration, and new format support were outside Pre10. This
|
||||
report does not claim that every EROFS feature was tested.
|
||||
|
||||
## Repository history and identities
|
||||
|
||||
The relevant pushed commits are:
|
||||
|
||||
| Commit | Purpose |
|
||||
| --- | --- |
|
||||
| `cdfcd79640f252830c4e507f65aa7387eaa98ae0` | Snapshot `repo-pre-10` from the current `repo-pre-9`. |
|
||||
| `b5d6f5ce0696407f9f1cb3f0a9f8cbab643eea49` | Add the Pre10 execution plan under `planning/pre10/`. |
|
||||
| `3c7c774b296a2ee90578a78f372aad5fd2edbec6` | Batch A compatibility cleanup and ordering. |
|
||||
| `8c246ea3c4dbf94b92d1f27a9d1b6b6eda582c31` | Batch B bounded metadata helper extraction. |
|
||||
| `d3c1cb90b21ae8a97f549bc256d120268e5d09e9` | Record the discovered `insmntque()` vnode lifecycle issue. |
|
||||
| `5c8a47e916b1521cb8a35ec4f546e5e16fb8c2dc` | Batch C decompressor request and descriptor alignment. |
|
||||
| `9fbf0d7e24084d2342ecd61eff21592b1a83d225` | Fix `insmntque()` failure ownership. |
|
||||
| `ff6586c2b24e155a3cbdf55b2ed80edb36d3e406` | Clarify the issue status after the source fix. This is the commit tested by the final smoke run. |
|
||||
|
||||
The snapshot report records the Pre9 source tree inherited by Pre10 as
|
||||
`e657e8a63b097b061670f75ca01947a568ef33d5`. The final smoke runner independently
|
||||
recorded these tested identities:
|
||||
|
||||
```text
|
||||
commit=ff6586c2b24e155a3cbdf55b2ed80edb36d3e406
|
||||
repo_pre_10_tree=3387e32efbcb0bec7e0bb57ecfc42daf9b962d28
|
||||
src_tree=ec684d8dbd7662070234da1fe947aba48a293db8
|
||||
```
|
||||
|
||||
Evidence: `/work/tests-dev/temp/pre10-smoke-final-20260813T102543Z/dut-identities.txt`.
|
||||
|
||||
## Batch A: compatibility cleanup and ordering
|
||||
|
||||
Batch A changed `src/internal.h`, `src/data.c`, and `src/zmap.c`.
|
||||
|
||||
Repository-wide consumer searches proved that the following declarations did
|
||||
not represent implemented FreeBSD behavior and had no source, Makefile, ABI,
|
||||
initializer, or field-access consumer:
|
||||
|
||||
- `EROFS_SYNC_DECOMPRESS_*`;
|
||||
- `EROFS_ZIP_CACHE_*`;
|
||||
- `struct erofs_buf` and `__EROFS_BUF_INITIALIZER`;
|
||||
- the unused `erofs_map_blocks.buf` member; and
|
||||
- `erofs_is_fileio_mode()`.
|
||||
|
||||
Removing these declarations improves maintainability because the FreeBSD tree
|
||||
no longer advertises Linux mechanisms that it does not implement. The real
|
||||
FreeBSD synchronous contiguous-buffer path and the Pre9 mount-owned decoded
|
||||
LZMA extent cache remain explicit and unchanged.
|
||||
|
||||
Declarations and existing function definitions were grouped by actual
|
||||
responsibility, closer to the Linux source's readable organization where the
|
||||
responsibilities match. Static call topology was preserved, and moved function
|
||||
bodies were compared for equivalence. No return value, allocation flag, lock,
|
||||
mapping flag, `bread`/`brelse` ownership rule, or runtime structure field was
|
||||
changed.
|
||||
|
||||
Detailed evidence: `repo-pre-10/docs/pre10-batch-a.md`.
|
||||
|
||||
## Batch B: bounded FreeBSD helper boundaries
|
||||
|
||||
Batch B changed `src/super.c`, `src/data.c`, and `src/inode.c`.
|
||||
|
||||
It extracted three `static` helpers with one direct caller each:
|
||||
|
||||
- `erofs_read_superblock()` isolates superblock read, fixed-size copy,
|
||||
validation, field decode, checksum, generation seed, and compression
|
||||
configuration parsing. `erofs_mountfs()` still owns mount allocation, GEOM
|
||||
transfer, device scanning, internal inode setup, publication, and the single
|
||||
mount cleanup path.
|
||||
- `erofs_fill_map_dev()` performs only the final `m_em`, `m_dif`, and `m_pa`
|
||||
assignments. Device selection, range checks, overflow checks, flat-device
|
||||
semantics, and `ENODEV`/`EINTEGRITY` decisions remain in `erofs_map_dev()`.
|
||||
- `erofs_fill_vnode()` performs only inode-derived vnode field setup. FreeBSD
|
||||
vnode allocation, locking, mount association, hash insertion, race handling,
|
||||
construction state, downgrade, publication, and cleanup remain in
|
||||
`erofs_vget()`.
|
||||
|
||||
These boundaries improve Linux/FreeBSD visual comparability at the function
|
||||
responsibility level while deliberately retaining the FreeBSD GEOM, vnode,
|
||||
hash, lock, and cleanup contracts. Linux lifecycle names such as `iget` or
|
||||
`fill_super` were not adopted where their semantics would be misleading.
|
||||
|
||||
Detailed evidence: `repo-pre-10/docs/pre10-batch-b.md`.
|
||||
|
||||
## Batch C: BSD decompressor request dispatch
|
||||
|
||||
Batch C changed `src/internal.h`, `src/decompressor.c`, `src/lz4.c`,
|
||||
`src/decompressor_lzma.c`, `src/decompressor_deflate.c`, and
|
||||
`src/decompressor_zstd.c`.
|
||||
|
||||
It introduced a stack-owned, synchronous, contiguous-buffer
|
||||
`z_erofs_decompress_req` and a descriptor table covering LZ4, LZMA, DEFLATE,
|
||||
ZSTD, SHIFTED, and INTERLACED. Codec entry points now use the Linux-comparable
|
||||
names `z_erofs_lz4_decompress`, `z_erofs_lzma_decompress`,
|
||||
`z_erofs_deflate_decompress`, and `z_erofs_zstd_decompress` because their
|
||||
functional roles are equivalent.
|
||||
|
||||
The interface remains BSD-native:
|
||||
|
||||
- no page, folio, bio, workqueue, XArray, shrinker, asynchronous request, or
|
||||
Linux ownership wrapper was introduced;
|
||||
- request fields borrow the existing compressed and decoded buffers only for
|
||||
the synchronous callback;
|
||||
- `zdata.c` still owns buffer release and LZMA decoded-cache publication;
|
||||
- plain SHIFTED/INTERLACED transforms remain in the existing dispatch model;
|
||||
- LZ4 padding behavior, partial-decoding source, LZMA dictionary validation,
|
||||
ZSTD conditional availability, and codec resource release remain unchanged;
|
||||
- configuration I/O errors preserve priority and backend failures remain
|
||||
normalized to the existing `EIO` result.
|
||||
|
||||
This gives third-party maintainers a recognizable request/descriptor and codec
|
||||
naming shape without importing Linux kernel runtime assumptions.
|
||||
|
||||
Detailed evidence: `repo-pre-10/docs/pre10-batch-c.md`.
|
||||
|
||||
## P1 vnode lifecycle finding and fix
|
||||
|
||||
Independent Batch B review found a pre-existing P1 ownership violation in
|
||||
`erofs_vget()`: after `insmntque()` returned an error, the old branch wrote
|
||||
through `vp->v_data` even though FreeBSD may already have executed `vgone()`
|
||||
and `vput()` and ended caller ownership of that vnode.
|
||||
|
||||
Commit `9fbf0d7e24084d2342ecd61eff21592b1a83d225` applied the minimal ownership
|
||||
fix. The error branch now frees only the independently allocated `en`, clears
|
||||
`*vpp`, returns the original error, and performs no further access, unlock,
|
||||
reclaim, or release operation on `vp`. The successful path, vnode hash race,
|
||||
lock state, errno, and later reclaim path were not changed.
|
||||
|
||||
Static ownership review confirms that the kernel failure path clears
|
||||
`v_data`, installs `dead_vnodeops`, and owns vnode cleanup; dead vnode reclaim
|
||||
does not release the filesystem's separately allocated `en`, so exactly one
|
||||
caller-side `free(en, M_EROFS)` remains necessary.
|
||||
|
||||
The source defect is fixed, but runtime closure is still pending. Closing the
|
||||
issue requires a dedicated mount/unmount race test that repeatedly creates or
|
||||
looks up uncached vnodes while normal and forced unmount are attempted, with
|
||||
kernel diagnostics capable of detecting stale vnode access, memory corruption,
|
||||
lock misuse, and double release. The ordinary smoke test below does not trigger
|
||||
or prove this teardown race.
|
||||
|
||||
Issue record:
|
||||
`repo-pre-10/issues/erofs-vget-insmntque-failure-use-after-release.md`.
|
||||
|
||||
## Static review result
|
||||
|
||||
The final static review accepted Batches A, B, and C and the P1 fix. Checks
|
||||
included changed-path allowlists, zero-consumer proof, prototype and backend
|
||||
symbol uniqueness, descriptor coverage and bounds, normalized moved-function
|
||||
body comparison, cleanup/ownership matrices, errno preservation, mount and
|
||||
vnode lifecycle ordering, cache ownership, forbidden Linux mechanism searches,
|
||||
conflict-marker searches, clean-worktree checks, `git diff --check`, and local
|
||||
`HEAD`/`xdm/main` agreement at each pushed boundary.
|
||||
|
||||
No new P0 or P1 defect was found in the three planned batches. Static review is
|
||||
not runtime proof. In particular, it does not close the dedicated vnode
|
||||
teardown race test or the older explicit-extent positive-fixture gap recorded
|
||||
under `repo-pre-10/issues/`.
|
||||
|
||||
## Initial inconclusive smoke attempts
|
||||
|
||||
Two isolated attempts preceded the final PASS. Neither is treated as a DUT
|
||||
failure or a PASS.
|
||||
|
||||
### Attempt 1
|
||||
|
||||
Evidence directory:
|
||||
`/work/tests-dev/temp/pre10-smoke-20260813T100326Z`.
|
||||
|
||||
The readiness probe began before the QEMU process had actually started, then
|
||||
performed repeated SSH handshakes while the TCG guest was still becoming
|
||||
responsive. Sources and fixtures were eventually transferred and the build log
|
||||
reached the final module link/strip stage, but the long SSH build session ended
|
||||
with transport status `255`. No reliable KLD SHA, `kldload`, or `kldstat`
|
||||
evidence was produced.
|
||||
|
||||
The first runner incorrectly continued into the plain case after the failed
|
||||
build/load stage. The guest reported `Invalid fstype`, while `results.txt`
|
||||
incorrectly recorded `mount_status=0` because the exit status was not captured
|
||||
immediately after `mount`. Since module loading was never proven and the
|
||||
runner's status recording was unsound, the mount result is not attributable to
|
||||
Pre10 and the attempt is **INCONCLUSIVE**, not FAIL or PASS.
|
||||
|
||||
### Attempt 2
|
||||
|
||||
Evidence directory:
|
||||
`/work/tests-dev/temp/pre10-smoke-retry-20260813T101136Z`.
|
||||
|
||||
The fresh guest booted and returned a valid FreeBSD identity after intermittent
|
||||
connection refusals, banner timeouts, and resets. The orchestration then exited
|
||||
almost immediately. The claimed SCP failure was not backed by an actual
|
||||
`scp-images.log`; only a failed attempt to tail that missing file remained.
|
||||
No build, module load, mount, or hash result exists. This attempt is also
|
||||
**INCONCLUSIVE** and provides no DUT verdict.
|
||||
|
||||
Both attempts stopped only their owned QEMU process, released ports `10040`
|
||||
and `10041`, deleted their disposable overlays, preserved the immutable base,
|
||||
and left guard PID `26318` and port `9222` unchanged.
|
||||
|
||||
The infrastructure diagnosis was recorded at
|
||||
`/work/tests-dev/fix-todo/pre10-smoke-ssh-banner-timeout.md`. Its original
|
||||
`PENDING_FIX` verdict describes those two attempts; the corrected final runner
|
||||
below subsequently completed the required targeted smoke.
|
||||
|
||||
## Corrected fail-fast runner
|
||||
|
||||
The successful run used a new directory and port `10042`, a fresh disposable
|
||||
overlay, 4096 MiB and two TCG CPUs, and a strictly ordered runner:
|
||||
|
||||
1. Verify exact Git, base-image, fixture, guard, and port identities before
|
||||
starting QEMU.
|
||||
2. Start QEMU and record its owned PID before beginning readiness checks.
|
||||
3. Wait for TCP, require two consecutive successful FreeBSD SSH identity
|
||||
checks, and establish one persistent SSH ControlMaster connection.
|
||||
4. Transfer the source archive, guest scripts, and all fixtures in one batch,
|
||||
then verify fixture hashes in the guest.
|
||||
5. Run the guest build as a background job that writes `build.rc` and a
|
||||
completion sentinel; poll the sentinel rather than depending on one long
|
||||
SSH session.
|
||||
6. Stop immediately unless the build return is zero, `erofs.ko` exists, its
|
||||
hash is recorded, `kldload` succeeds, and `kldstat -n erofs` proves the
|
||||
module is loaded.
|
||||
7. Run each filesystem case separately and immediately record attach, mount,
|
||||
mount-proof, hash, unmount, and detach return codes. A missing proof or
|
||||
nonzero result stops the runner and cannot be converted to PASS.
|
||||
8. Review guest cleanup and `dmesg`, unload the module, and prove it is absent.
|
||||
9. Use the cleanup trap to stop only the recorded QEMU PID, release only the
|
||||
run-owned port and overlay, and revalidate the immutable base and guard VM.
|
||||
|
||||
Runner evidence:
|
||||
`/work/tests-dev/temp/pre10-smoke-final-20260813T102543Z/runner.sh` and
|
||||
`runner.log`.
|
||||
|
||||
## Final targeted smoke result
|
||||
|
||||
Final evidence directory:
|
||||
`/work/tests-dev/temp/pre10-smoke-final-20260813T102543Z`.
|
||||
|
||||
Overall result: **PASS** for the targeted Pre10 smoke scope.
|
||||
|
||||
### Isolation
|
||||
|
||||
- Immutable base image mode before and after: `0444`.
|
||||
- Immutable base image SHA-256 before and after:
|
||||
`67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef`.
|
||||
- The `.bp` was not booted or modified directly; the run used a disposable
|
||||
qcow2 overlay.
|
||||
- Guard PID: `26318`; guard SSH port: `9222`.
|
||||
- Guard command identity and `/proc` start value `1102996924` matched before
|
||||
and after, and port `9222` remained reachable.
|
||||
|
||||
Evidence: `base-before.txt`, `cleanup-status.txt`, `guard-before.txt`,
|
||||
`guard-command-before.txt`, `guard-command-after.txt`,
|
||||
`guard-start-before.txt`, and `guard-start-after.txt` in the final evidence
|
||||
directory.
|
||||
|
||||
### KLD build, load, and unload
|
||||
|
||||
- FreeBSD guest build return: `0`.
|
||||
- Built KLD SHA-256:
|
||||
`4ce2d44a0902502a40f07805606485c99869371b3cbab1c70ee19a8ac29d90f1`.
|
||||
- The loaded module hash matched the built module hash.
|
||||
- `kldstat` showed `erofs.ko` loaded as module ID `5`.
|
||||
- `kldunload` succeeded, and the final `kldstat -n erofs` correctly reported
|
||||
that no such loaded module remained.
|
||||
|
||||
Evidence: `build-result.out`, `build-result.rc`, `module-load.out`,
|
||||
`module-load.rc`, and `guest-evidence.tar.gz`.
|
||||
|
||||
### Filesystem cases
|
||||
|
||||
| Case | Mounted file SHA-256 | Time | Result |
|
||||
| --- | --- | ---: | --- |
|
||||
| Plain `/data.txt` | `056f8f7585667dc695e2edf936deaf84cfee0f88671ba6cd5be22ce890763433` | `0s` | PASS |
|
||||
| LZ4 `/compressed.bin` | `3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880` | `5s` | PASS |
|
||||
| LZMA full `/level.dat` | `ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461` | `2s` | PASS |
|
||||
|
||||
Each case recorded zero returns for md attach, EROFS mount, mount proof,
|
||||
full-file hash, unmount, and md detach. The exact fixture image hashes were:
|
||||
|
||||
```text
|
||||
plain image 3785ca07e7bd16f6c611191596ae0314253c0ae9b7217a4b22de25799b0f08ac
|
||||
LZ4 image 967cc1b625546f9f9f881472e71cc3d849c65feb4e98e67fbfdc9b90a4be6dda
|
||||
LZMA image 32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9
|
||||
```
|
||||
|
||||
Evidence: `fixture-host-sha256.txt`, `results.txt`, and the per-case files in
|
||||
`guest-evidence.tar.gz`.
|
||||
|
||||
### Kernel messages and cleanup
|
||||
|
||||
The post-test `dmesg` delta and suspect scan were empty: no EROFS mount,
|
||||
integrity, decompression, panic, or assertion error was found. After all cases,
|
||||
only the guest root filesystem and `devfs` remained mounted, no test md device
|
||||
remained, and the EROFS module was unloaded.
|
||||
|
||||
Host cleanup also passed:
|
||||
|
||||
- the run-owned QEMU process stopped;
|
||||
- port `10042` was released;
|
||||
- the disposable overlay was deleted;
|
||||
- the base image mode and hash were unchanged; and
|
||||
- the guard VM remained unchanged and reachable.
|
||||
|
||||
Evidence: `dmesg-delta.txt`, `dmesg-suspect.txt`, `final-guest-state.out`,
|
||||
`cleanup-status.txt`, and `guest-evidence.tar.gz`.
|
||||
|
||||
## Validation limits and conclusion
|
||||
|
||||
Pre10's planned source changes are complete, independently statically reviewed,
|
||||
committed, pushed, built in a FreeBSD guest, and covered by the targeted plain,
|
||||
LZ4, and LZMA smoke run. That targeted scope passed at tested commit
|
||||
`ff6586c2b24e155a3cbdf55b2ed80edb36d3e406`.
|
||||
|
||||
No full feature test and no `/work/tests-dev/test_all.py` run was performed.
|
||||
This report therefore does not claim all features, codecs, mapping layouts,
|
||||
multi-device behavior, partial references, tailpacking, memory pressure, or
|
||||
concurrent teardown behavior passed.
|
||||
|
||||
A feature-specific test is still required to close the fixed `insmntque()`
|
||||
issue's runtime-validation status: the dedicated normal/forced mount-unmount
|
||||
race with uncached vnode creation and kernel diagnostics described above. It
|
||||
is desirable and required for issue closure, but it was not run because the
|
||||
instruction for Pre10 was smoke testing only and explicitly excluded feature
|
||||
testing.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Pre11 Baseline
|
||||
|
||||
Pre11 was created as an exact snapshot copy of `repo-pre-10` before any
|
||||
Pre11 planning or implementation changes.
|
||||
|
||||
## Source identity
|
||||
|
||||
- Repository source commit: `c191517f3799291852f8673e90b0f1be8427d3a9`
|
||||
- `repo-pre-10` tree: `53d5c5fadc2d1fabf83346eadadec44c97c85c10`
|
||||
- `repo-pre-10/src` tree: `ec684d8dbd7662070234da1fe947aba48a293db8`
|
||||
|
||||
## Destination identity before this document
|
||||
|
||||
- `repo-pre-11` tree: `53d5c5fadc2d1fabf83346eadadec44c97c85c10`
|
||||
- `repo-pre-11/src` tree: `ec684d8dbd7662070234da1fe947aba48a293db8`
|
||||
|
||||
## Exact copy verification
|
||||
|
||||
Before this baseline document was added, `repo-pre-10` and `repo-pre-11`
|
||||
were verified identical by:
|
||||
|
||||
- recursive byte-for-byte content comparison;
|
||||
- complete file and directory manifest comparison;
|
||||
- file type, mode, and symbolic-link target comparison;
|
||||
- identical complete subtree tree IDs;
|
||||
- identical `src` subtree tree IDs.
|
||||
|
||||
The snapshot contains the same 307 tracked files as `repo-pre-10`. No nested
|
||||
Git repository, external untracked file, generated image, temporary artifact,
|
||||
or file larger than 10 MiB was introduced by the copy.
|
||||
|
||||
## Pre11 state
|
||||
|
||||
No implementation, build, configuration, or behavior change has occurred.
|
||||
This file only records the Pre11 snapshot baseline.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Pre11 Batch A
|
||||
|
||||
This batch performs two mechanical vocabulary alignments:
|
||||
|
||||
- `struct erofs_mount.block_bits` is renamed to `blkszbits`.
|
||||
- `erofs_fill_map_dev()` is renamed to `erofs_fill_from_devinfo()`.
|
||||
|
||||
No types, expressions, control flow, ownership rules, error handling, or runtime behavior were changed. Semantic type alias changes were deferred because they were not needed for this pure mechanical batch.
|
||||
|
||||
Validation is limited to identifier occurrence checks, diff inspection, and `git diff --check`. Build and runtime testing are deferred to the later Pre11 validation stage.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Pre11 Batch B: Vnode Operation Scaffolding
|
||||
|
||||
## Scope
|
||||
|
||||
This batch is a behavior-preserving cleanup limited to vnode operation
|
||||
scaffolding:
|
||||
|
||||
- removed the unused `EROFS_MOUNT_XATTR_USER` option bit;
|
||||
- removed the zero-consumer `erofs_node.vnode` field and its only assignment;
|
||||
- grouped VOP forward declarations and `erofs_vnodeops` initializers by
|
||||
responsibility.
|
||||
|
||||
No function definitions, VOP registrations, lock or reclaim behavior,
|
||||
`vnode_create_vobject()` error handling, or FIFO operations were changed.
|
||||
|
||||
## Consumer Audit
|
||||
|
||||
Before the edit, `EROFS_MOUNT_XATTR_USER` appeared only at its definition.
|
||||
The `erofs_node.vnode` member appeared only in the structure definition and in
|
||||
the single assignment performed by `erofs_vget()`; it had no read, address, ABI,
|
||||
initializer, or offset consumer.
|
||||
|
||||
After the edit, both removed symbols have zero source-tree matches.
|
||||
|
||||
## VOP Vector Equivalence
|
||||
|
||||
Before reordering:
|
||||
|
||||
- `erofs_vnodeops`: 24 raw entries, 24 unique normalized `field=value` entries;
|
||||
- `erofs_fifoops`: 14 raw entries, 14 unique normalized `field=value` entries.
|
||||
|
||||
After reordering:
|
||||
|
||||
- `erofs_vnodeops`: 24 raw entries, 24 unique entries, with the sorted
|
||||
normalized set identical to the before snapshot;
|
||||
- `erofs_fifoops`: 14 raw entries, 14 unique entries, with both the sorted set
|
||||
and original entry sequence identical to the before snapshot.
|
||||
|
||||
## Validation
|
||||
|
||||
The batch uses static checks only:
|
||||
|
||||
- normalized before/after VOP vector set comparison;
|
||||
- raw entry count versus unique entry count;
|
||||
- removed-symbol zero-consumer search;
|
||||
- changed-path whitelist;
|
||||
- `git diff --check` and conflict-marker scan.
|
||||
|
||||
No build, QEMU smoke test, or feature test was run for this mechanical batch.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Pre11 Batch C: ACL Parsing Responsibilities
|
||||
|
||||
## Scope
|
||||
|
||||
This batch mechanically separates POSIX ACL wire-format parsing from the
|
||||
FreeBSD vnode and xattr acquisition path.
|
||||
|
||||
Modified files:
|
||||
|
||||
- `src/xattr.c`
|
||||
- `docs/pre11-batch-c.md`
|
||||
|
||||
No xattr body loading, header-only xattr behavior, namespace handling, public
|
||||
VOP interface, build configuration, or test infrastructure was changed.
|
||||
|
||||
## Responsibility Split
|
||||
|
||||
`erofs_get_acl()` continues to own:
|
||||
|
||||
- mount option and ACL type validation;
|
||||
- the default-ACL directory restriction;
|
||||
- no-ACL filter handling and mode fallback;
|
||||
- xattr namespace and name selection;
|
||||
- both `erofs_getxattr()` stages;
|
||||
- FreeBSD `uio` and `iovec` setup;
|
||||
- `ENOATTR` fallback and the stack input buffer.
|
||||
|
||||
The new `erofs_posix_acl_from_xattr()` receives an already-read buffer and
|
||||
owns only wire-format validation and ACL population. It borrows both the input
|
||||
buffer and output ACL and performs no allocation, release, lookup, or vnode
|
||||
operation.
|
||||
|
||||
`erofs_acl_from_mode()` now receives the inode mode directly. This preserves
|
||||
the original fallback writes while preventing the parser from depending on an
|
||||
`erofs_node`.
|
||||
|
||||
## Moved-Code Mapping
|
||||
|
||||
The parsing block formerly at the end of `erofs_get_acl()` was moved in the
|
||||
same statement order into `erofs_posix_acl_from_xattr()`:
|
||||
|
||||
1. Header length and entry-size remainder validation.
|
||||
2. Header copy and version validation.
|
||||
3. Entry count calculation and maximum check.
|
||||
4. Zero-entry mode fallback.
|
||||
5. `acl_cnt` assignment and phase initialization.
|
||||
6. Permission validation before tag-phase validation.
|
||||
7. Tag phase transitions and `UINT32_MAX` rules.
|
||||
8. Duplicate named user and group ID checks.
|
||||
9. ACL entry writes and undefined-ID mapping.
|
||||
10. The short-circuit `phase != 6 || acl_posix1e_check(aclp) != 0` check.
|
||||
|
||||
No ACL zeroing or additional field initialization was added. Partial ACL
|
||||
mutation on malformed input remains possible exactly as before.
|
||||
|
||||
## Branch Matrix
|
||||
|
||||
| Input or state | Preserved result |
|
||||
| --- | --- |
|
||||
| POSIX ACL mount option disabled | `EOPNOTSUPP` in caller |
|
||||
| Unsupported ACL type | `EINVAL` in caller |
|
||||
| Default ACL requested for non-directory | `EINVAL` in caller |
|
||||
| No-ACL filter match | Mode-derived ACL in caller |
|
||||
| ACL xattr absent | Mode-derived ACL in caller |
|
||||
| Xattr lookup/read failure | Original error from caller |
|
||||
| Oversized xattr or nonzero UIO residual | `EINTEGRITY` in caller |
|
||||
| Short or misaligned wire value | `EINTEGRITY` in parser |
|
||||
| Unsupported wire version | `EINTEGRITY` in parser |
|
||||
| Entry count above limit | `EINTEGRITY` in parser |
|
||||
| Zero entries | Mode-derived ACL in parser |
|
||||
| Invalid permission, phase, tag, or ID | `EINTEGRITY` in parser |
|
||||
| Duplicate named user/group ID | `EINTEGRITY` in parser |
|
||||
| Missing required mask or incomplete phase | `EINTEGRITY` in parser |
|
||||
| Valid ACL | Identical ACL entry population and success |
|
||||
|
||||
## Resource And Error Audit
|
||||
|
||||
- The input buffer remains stack-owned by `erofs_get_acl()`.
|
||||
- The parser does not allocate, free, or retain pointers.
|
||||
- There are no new cleanup paths.
|
||||
- Xattr errors, UIO residual errors, wire errors, and ACL validation errors
|
||||
retain their previous ordering.
|
||||
- `erofs_xattr_load_body()` and its release paths were not modified.
|
||||
- The optional header validation helper was intentionally omitted to avoid
|
||||
touching the known header-only behavior.
|
||||
|
||||
## Static Verification
|
||||
|
||||
The batch is validated with:
|
||||
|
||||
- a strict two-file path whitelist;
|
||||
- unique definitions of `erofs_get_acl()`, `erofs_acl_from_mode()`, and
|
||||
`erofs_posix_acl_from_xattr()`;
|
||||
- pre/post comparison of parser returns, phase transitions, ACL writes, and
|
||||
duplicate-ID checks;
|
||||
- `git diff --check`;
|
||||
- confirmation that `erofs_xattr_load_body()` is absent from the source diff.
|
||||
|
||||
No build, QEMU smoke test, or feature test was run for this mechanical split.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Pre11 Batch D
|
||||
|
||||
## Scope
|
||||
|
||||
- Rename `src/lz4.c` to `src/decompressor_lz4.c`.
|
||||
- Update the source list and current architecture references to the new filename.
|
||||
|
||||
## Equivalence
|
||||
|
||||
- The pre-rename `lz4.c` blob and renamed `decompressor_lz4.c` blob are identical.
|
||||
- Byte comparison confirms the renamed source content is unchanged.
|
||||
- Rename detection reports a 100% rename.
|
||||
- LZ4 definitions, declarations, descriptor references, and `lz4_finish` call counts are unchanged.
|
||||
|
||||
## Behavior and Testing
|
||||
|
||||
- This batch changes filenames and documentation only; it makes no behavior changes.
|
||||
- No build, QEMU run, feature test, or other test was run.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Pre11 Batch E: Mount Device Argument Cleanup
|
||||
|
||||
## Scope
|
||||
|
||||
This batch consolidates caller-owned `device.N` argument cleanup in
|
||||
`erofs_mount()` and removes two impossible allocation checks. It does not
|
||||
change mount option semantics, GEOM ownership, device slot validation, mount
|
||||
error text, or any filesystem behavior.
|
||||
|
||||
Modified files:
|
||||
|
||||
- `src/super.c`
|
||||
- `docs/pre11-batch-e.md`
|
||||
|
||||
## Changes
|
||||
|
||||
After `erofs_parse_device_options()` succeeds, every exit from
|
||||
`erofs_mount()` now reaches one `out_args` label. Parse failure still returns
|
||||
directly because no caller-owned argument array has been transferred.
|
||||
|
||||
The operation order remains:
|
||||
|
||||
1. `erofs_parse_device_options()`
|
||||
2. `vfs_filteropt()`
|
||||
3. `vfs_getopt()`
|
||||
4. `erofs_open_device()`
|
||||
5. `erofs_update_iosize_max()`
|
||||
6. `erofs_mountfs()`
|
||||
7. `erofs_free_device_args()`
|
||||
8. `vfs_mountedfrom()`
|
||||
9. `erofs_statfs()`
|
||||
|
||||
`out_args` only frees copied device arguments. It does not inspect or release
|
||||
`primary`. The existing `erofs_mountfs()` ownership transfer and all GEOM
|
||||
cleanup paths remain unchanged.
|
||||
|
||||
The checks for `NULL` immediately following allocation of `packed_inode` and
|
||||
`metabox_en` were removed. Both allocations retain `M_WAITOK | M_ZERO`, so a
|
||||
successful return cannot produce `NULL`. No other allocation checks or flags
|
||||
were changed.
|
||||
|
||||
## Ownership Paths
|
||||
|
||||
| Path | Copied arguments | Primary device | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| Parse failure | No caller ownership | Not opened | Return parser error directly |
|
||||
| Option filter failure | Freed at `out_args` | Not opened | Return `EINVAL` |
|
||||
| Invalid or missing `from` | Freed at `out_args` | Not opened | Return `EINVAL` |
|
||||
| Primary open failure | Freed at `out_args` | Open helper retains its existing cleanup contract | Return open error |
|
||||
| Mount setup failure | Freed at `out_args` | Ownership already transferred at `erofs_mountfs()` entry | Return mount error |
|
||||
| Success | Freed at `out_args` | Owned by the mounted filesystem | Publish mounted-from and run `statfs()` |
|
||||
|
||||
## Static Verification
|
||||
|
||||
- `erofs_free_device_args()` has one caller after the change.
|
||||
- `erofs_mountfs()` and `erofs_sb_free()` are unchanged.
|
||||
- The relative order of option filtering, option access, primary open, I/O
|
||||
sizing, mount setup, argument cleanup, mounted-from publication, and statfs
|
||||
is unchanged.
|
||||
- Existing errno values and mount error strings are unchanged.
|
||||
- Duplicate and missing external-device slot behavior is unchanged.
|
||||
- `git diff --check` passes.
|
||||
- The diff is restricted to the two declared Batch E files.
|
||||
|
||||
## Validation Status
|
||||
|
||||
No build, QEMU smoke test, or feature test was run for this batch. Runtime
|
||||
validation is deferred to the final Pre11 build and targeted smoke test.
|
||||
@@ -0,0 +1,480 @@
|
||||
# Pre11 Completion and Smoke Report
|
||||
|
||||
## Status
|
||||
|
||||
Pre11 is complete for its approved mechanical maintenance scope.
|
||||
|
||||
- Final implementation commit tested: `040fc69025c5031436205c3acd421be1d95fe86b`
|
||||
- Final `repo-pre-11` tree: `f0cca92670c76ab13cc5b9353d5aeb993effa6e2`
|
||||
- Final `repo-pre-11/src` tree: `c4aac4d69cb25a4b049239d0c1f422dcb89465d6`
|
||||
- Static review: `ACCEPT`, with no P0-P3 findings in the included changes
|
||||
- FreeBSD KLD build: `PASS`, using `WITH_ZSTDIO=0`
|
||||
- Targeted plain/LZ4/LZMA QEMU smoke: `PASS`
|
||||
- Full feature test and `test_all.py`: `NOT RUN`
|
||||
|
||||
This report does not claim full feature validation. Pre11 deliberately contains
|
||||
mechanical naming, responsibility, dead-scaffolding, file-layout, and cleanup
|
||||
changes that could be reviewed for behavioral equivalence and then covered by a
|
||||
focused build and smoke run. Behavior changes requiring purpose-built fixtures
|
||||
remain deferred.
|
||||
|
||||
## Snapshot and Planning
|
||||
|
||||
Pre11 was created from the completed Pre10 tree in:
|
||||
|
||||
```text
|
||||
0483dcb41c2a980badb829ff4d17361bd1fec930
|
||||
snapshot: create repo-pre-11 from repo-pre-10
|
||||
```
|
||||
|
||||
At the snapshot boundary, `repo-pre-10/src` and `repo-pre-11/src` were both:
|
||||
|
||||
```text
|
||||
ec684d8dbd7662070234da1fe947aba48a293db8
|
||||
```
|
||||
|
||||
The executable Pre11 plan was added in:
|
||||
|
||||
```text
|
||||
9ad1fa0cf8ba251b574da033bf0c9fad83acaa38
|
||||
docs: add pre11 execution plan
|
||||
```
|
||||
|
||||
The original plan included several candidates that would have changed visible
|
||||
filesystem behavior. An independent boundary review narrowed the release in:
|
||||
|
||||
```text
|
||||
c89c228ac1817cfd0337905b39247245eaa67f3b
|
||||
docs: narrow pre11 execution boundaries
|
||||
```
|
||||
|
||||
The narrowed scope retained only work that could preserve control flow, errno,
|
||||
on-disk interpretation, vnode and GEOM ownership, iterator order, decompressor
|
||||
semantics, and cache lifetime. The following candidates were removed from
|
||||
implementation because honest validation would require targeted feature tests:
|
||||
|
||||
- root vnode type rejection;
|
||||
- zero-length mapping behavior in the UIO reader;
|
||||
- header-only xattr semantics;
|
||||
- duplicate or missing `device.N` behavior;
|
||||
- direct propagation of `vnode_create_vobject()` errors;
|
||||
- broad map, inode, directory, and name-lookup interface reshaping.
|
||||
|
||||
This narrowing allowed Pre11 to remain a comparatively large maintenance
|
||||
release without mixing low-risk structural alignment with unvalidated semantic
|
||||
changes.
|
||||
|
||||
## Batch A: Type and Vocabulary Alignment
|
||||
|
||||
Commit:
|
||||
|
||||
```text
|
||||
b4e38c9fb15df127470d70bc144404f1f3afa2af
|
||||
pre11: align mount and device helper vocabulary
|
||||
```
|
||||
|
||||
Exact changes:
|
||||
|
||||
- renamed `struct erofs_mount.block_bits` to `blkszbits` across its consumers;
|
||||
- renamed the private `erofs_fill_map_dev()` helper to
|
||||
`erofs_fill_from_devinfo()`;
|
||||
- added the Batch A implementation report.
|
||||
|
||||
Linux-maintenance benefit:
|
||||
|
||||
- `blkszbits` matches established EROFS vocabulary and makes comparisons with
|
||||
Linux mount geometry code more direct;
|
||||
- `erofs_fill_from_devinfo()` describes the same responsibility as the Linux
|
||||
helper without importing Linux block-device objects into FreeBSD.
|
||||
|
||||
BSD invariants retained:
|
||||
|
||||
- field type, width, units, expressions, overflow handling, and structure
|
||||
layout were unchanged;
|
||||
- the helper remained a private FreeBSD device-map field filler;
|
||||
- GEOM provider selection, range checks, flat-device behavior, errno, and
|
||||
physical I/O remained unchanged;
|
||||
- no broad or search-driven integer type replacement was performed.
|
||||
|
||||
Static checks confirmed 48 intended `block_bits` replacements, zero remaining
|
||||
old identifiers, four helper-name replacements, zero stale helper references,
|
||||
and a source diff containing only the approved identifier changes.
|
||||
|
||||
## Batch B: Vnode Operation Scaffolding
|
||||
|
||||
Commit:
|
||||
|
||||
```text
|
||||
67625d3afebb9142e69b19afd08cdfc1d2adaac5
|
||||
refactor: clean up vnode operation scaffolding
|
||||
```
|
||||
|
||||
Exact changes:
|
||||
|
||||
- removed the unused `EROFS_MOUNT_XATTR_USER` option bit;
|
||||
- removed the zero-consumer `erofs_node.vnode` member and its only assignment;
|
||||
- grouped VOP declarations and `erofs_vnodeops` initializers by responsibility;
|
||||
- added the Batch B implementation report.
|
||||
|
||||
Linux-maintenance benefit:
|
||||
|
||||
- removes misleading compatibility-shaped state that had no consumer;
|
||||
- presents vnode operations in a responsibility-oriented order that is easier
|
||||
to compare with upstream filesystem responsibilities while retaining the
|
||||
native FreeBSD operation table.
|
||||
|
||||
BSD invariants retained:
|
||||
|
||||
- no VOP function definition or registration changed;
|
||||
- `erofs_vnodeops` retained 24 unique `field=value` entries;
|
||||
- `erofs_fifoops` retained 14 unique entries and its original sequence;
|
||||
- `fifo_specops`, vnode locking, hash insertion, reclaim, pager behavior, and
|
||||
`vnode_create_vobject()` errno translation were unchanged.
|
||||
|
||||
The removed symbols had no reads, address consumers, initializer dependencies,
|
||||
offset consumers, or external ABI use.
|
||||
|
||||
## Batch C: ACL Parsing Responsibilities
|
||||
|
||||
Commit:
|
||||
|
||||
```text
|
||||
a86b5cac4d193d131de8870bca4132fdc881f992
|
||||
erofs: split ACL parsing responsibilities
|
||||
```
|
||||
|
||||
Exact changes:
|
||||
|
||||
- extracted private `erofs_posix_acl_from_xattr()` from `erofs_get_acl()`;
|
||||
- changed the private mode fallback helper to receive the inode mode directly;
|
||||
- left xattr acquisition and all FreeBSD VOP/UIO responsibilities in the
|
||||
caller;
|
||||
- added the Batch C implementation report.
|
||||
|
||||
Linux-maintenance benefit:
|
||||
|
||||
- separates wire-format ACL parsing from filesystem acquisition and VOP glue,
|
||||
matching the upstream responsibility split more closely;
|
||||
- gives maintainers a bounded parser to compare without introducing Linux ACL
|
||||
objects, RCU, xattr handlers, or inode lifecycle assumptions.
|
||||
|
||||
BSD invariants retained:
|
||||
|
||||
- mount-option checks, ACL type validation, default-ACL directory checks,
|
||||
namespace selection, both `erofs_getxattr()` stages, UIO setup, and `ENOATTR`
|
||||
fallback remain in `erofs_get_acl()`;
|
||||
- parser validation order, positive errno, tag phases, duplicate ID checks,
|
||||
`UINT32_MAX` handling, partial ACL writes, and final
|
||||
`acl_posix1e_check()` ordering remain unchanged;
|
||||
- input storage remains caller-owned stack memory, with no new allocation or
|
||||
cleanup path;
|
||||
- `erofs_xattr_load_body()` and the known header-only xattr behavior were not
|
||||
changed.
|
||||
|
||||
Static comparison confirmed equivalent branch, error, phase-transition, and
|
||||
ACL-population behavior.
|
||||
|
||||
## Batch D: LZ4 Backend File Responsibility
|
||||
|
||||
Commit:
|
||||
|
||||
```text
|
||||
e631e33a1b8c053ebcb2d737af33e363cba48b34
|
||||
erofs: align LZ4 backend file responsibility
|
||||
```
|
||||
|
||||
Exact changes:
|
||||
|
||||
- renamed `src/lz4.c` to `src/decompressor_lz4.c`;
|
||||
- updated the Makefile source entry;
|
||||
- updated current architecture documentation references;
|
||||
- added the Batch D implementation report.
|
||||
|
||||
Linux-maintenance benefit:
|
||||
|
||||
- makes the filename communicate that the translation unit is the LZ4 codec
|
||||
backend beside `decompressor_lzma.c`, `decompressor_deflate.c`, and
|
||||
`decompressor_zstd.c`;
|
||||
- reduces unnecessary file-layout differences when maintainers inspect codec
|
||||
implementations across the independent Linux and FreeBSD repositories.
|
||||
|
||||
BSD invariants retained:
|
||||
|
||||
- Git identified a 100% rename;
|
||||
- the old and new source blobs are both
|
||||
`2cc19f5eb0c283e12ba0a3a4334b8817a1686888`;
|
||||
- function bodies, request ABI, descriptor registration, input/output bounds,
|
||||
partial decode behavior, and error normalization were unchanged;
|
||||
- historical reports and historical test evidence were not rewritten.
|
||||
|
||||
## Batch E: Mount Device Argument Cleanup
|
||||
|
||||
Commit:
|
||||
|
||||
```text
|
||||
040fc69025c5031436205c3acd421be1d95fe86b
|
||||
erofs: consolidate mount device argument cleanup
|
||||
```
|
||||
|
||||
Exact changes:
|
||||
|
||||
- consolidated caller-owned copied `device.N` argument release into one
|
||||
`out_args` exit in `erofs_mount()`;
|
||||
- removed two impossible NULL checks immediately following
|
||||
`M_WAITOK | M_ZERO` allocations;
|
||||
- added the Batch E implementation report.
|
||||
|
||||
Linux-maintenance benefit:
|
||||
|
||||
- makes mount setup ownership and cleanup easier to audit by reducing repeated
|
||||
release sites;
|
||||
- removes defensive branches that contradict the FreeBSD `M_WAITOK` contract,
|
||||
keeping BSD-specific allocation behavior explicit instead of emulating a
|
||||
nullable Linux allocation path.
|
||||
|
||||
BSD invariants retained:
|
||||
|
||||
- operation order remains parse, filter, get option, open primary, update I/O
|
||||
size, mount setup, free copied arguments, publish mounted-from, and statfs;
|
||||
- parse failure still returns before caller ownership exists;
|
||||
- `out_args` releases only copied arguments and never releases `primary`;
|
||||
- `erofs_mountfs()` still takes ownership of `primary` at entry;
|
||||
- `erofs_mountfs()`, `erofs_sb_free()`, reverse external-device cleanup, errno,
|
||||
and mount error text are unchanged;
|
||||
- duplicate and missing external-device slot behavior remains deferred.
|
||||
|
||||
## Static Review
|
||||
|
||||
Independent reviews were performed after the individual batches and again over
|
||||
the complete source range from `0483dcb` through `040fc690`.
|
||||
|
||||
The final review found no P0-P3 issue in the included Pre11 source changes and
|
||||
accepted all five batches. It confirmed:
|
||||
|
||||
- the source changes were confined to the approved Batch A-E paths;
|
||||
- no deferred behavior fix entered the source;
|
||||
- old identifiers had no stale consumers and new private helpers had unique
|
||||
definitions and expected call counts;
|
||||
- both VOP vectors retained the same registration mappings;
|
||||
- ACL acquisition, parsing, fallback, errno, and partial-write behavior were
|
||||
preserved;
|
||||
- the LZ4 backend was a byte-identical rename and the Makefile contained the
|
||||
new filename once;
|
||||
- mount cleanup retained error order and GEOM ownership;
|
||||
- uncompressed mapping interfaces, directory/name lookup, decompressor request
|
||||
ABI, LZMA cache policy, disk structures, and Linux reference sources were not
|
||||
changed;
|
||||
- `git diff --check` passed and the implementation worktree was clean before
|
||||
runtime validation.
|
||||
|
||||
The final source delta from the snapshot contains 202 insertions and 188
|
||||
deletions across ten source paths, including the 100% LZ4 file rename. Much of
|
||||
that textual delta is identifier replacement, declaration/vector reordering,
|
||||
or moved ACL parser code rather than new behavior.
|
||||
|
||||
## First Smoke Attempt: Infrastructure Failure
|
||||
|
||||
Evidence directory:
|
||||
|
||||
```text
|
||||
/work/tests-dev/temp/pre11-smoke-final-20260813T122923Z
|
||||
```
|
||||
|
||||
Result: `FAIL`, specifically an infrastructure failure before DUT transfer or
|
||||
execution.
|
||||
|
||||
The guest reached FreeBSD and two SSH identity probes succeeded, but the first
|
||||
runner opened an SSH ControlMaster using a detached invocation. The open command
|
||||
returned success and created the control socket, then the master terminated or
|
||||
lost its connection before the immediate health check. The check failed with:
|
||||
|
||||
```text
|
||||
Control socket connect(.../control.sock): Connection refused
|
||||
```
|
||||
|
||||
The test stopped before source transfer, KLD build, module load, or any EROFS
|
||||
mount. Therefore this attempt is not a PASS, but it is also not evidence of a
|
||||
Pre11 build or driver failure. Its source archive SHA was:
|
||||
|
||||
```text
|
||||
5bbffb101364f350fe1a3771b6f018bc10a68785d8c55cc2a186273a074e9182
|
||||
```
|
||||
|
||||
The owned QEMU stopped, port `10043` was released, its overlay was removed, the
|
||||
base image remained unchanged, and the retained guard VM remained reachable.
|
||||
The run's cleanup status was nonzero only because closing the already-dead
|
||||
ControlMaster returned an error.
|
||||
|
||||
## Corrected Smoke Retry
|
||||
|
||||
Evidence directory:
|
||||
|
||||
```text
|
||||
/work/tests-dev/temp/pre11-smoke-retry-final-20260813T124214Z
|
||||
```
|
||||
|
||||
Result: `PASS`.
|
||||
|
||||
The retry used an SSH master process in normal foreground mode but launched it
|
||||
in the runner shell background, without `ssh -f`. The runner captured the real
|
||||
master PID, repeatedly required both `kill -0` and `ssh -O check` to succeed,
|
||||
and refused to transfer sources unless the master remained alive. Long build
|
||||
work ran inside the guest with a completion sentinel, so one long SSH command
|
||||
was not treated as the build lifetime.
|
||||
|
||||
Tested identities:
|
||||
|
||||
```text
|
||||
commit: 040fc69025c5031436205c3acd421be1d95fe86b
|
||||
repo-pre-11 tree: f0cca92670c76ab13cc5b9353d5aeb993effa6e2
|
||||
src tree: c4aac4d69cb25a4b049239d0c1f422dcb89465d6
|
||||
source archive: 179b80365c26295770afab58f1209ae3fffd73182ada0bcf97ea027904f781e9
|
||||
guest: FreeBSD 15.0-RELEASE-p8
|
||||
```
|
||||
|
||||
The archive hashes differ between attempts because separately generated gzip
|
||||
archives are not required to be byte-reproducible. Both identity files name the
|
||||
same committed repository and source trees; only the passing retry is used as
|
||||
runtime evidence.
|
||||
|
||||
## Build and Module Lifecycle
|
||||
|
||||
The committed `repo-pre-11` archive was transferred to the disposable guest,
|
||||
validated there, extracted, and built with:
|
||||
|
||||
```sh
|
||||
make WITH_ZSTDIO=0
|
||||
```
|
||||
|
||||
Results:
|
||||
|
||||
- guest build return code: `0`;
|
||||
- `erofs.ko` SHA256:
|
||||
`77ce41bff5cb7d7c934dd9dba20ba06c20b660ad15ebfc4210f86f6473dffbf7`;
|
||||
- `kldload /root/pre11-smoke/erofs.ko`: success;
|
||||
- `kldstat -n erofs`: success, reporting `erofs.ko` loaded;
|
||||
- all smoke mounts and md providers were released;
|
||||
- `kldunload erofs`: success;
|
||||
- the post-unload `kldstat -n erofs` check confirmed the module was absent.
|
||||
|
||||
`WITH_ZSTDIO=1` was not built and is not claimed as tested.
|
||||
|
||||
## Smoke Cases
|
||||
|
||||
Each case used an independently attached vnode-backed md provider, required a
|
||||
successful EROFS mount to be visible in `mount -p`, computed the complete target
|
||||
file hash, then unmounted and detached the provider before the next case.
|
||||
|
||||
| Case | Target SHA256 | Elapsed | Provider | Result |
|
||||
| --- | --- | ---: | --- | --- |
|
||||
| Plain | `056f8f7585667dc695e2edf936deaf84cfee0f88671ba6cd5be22ce890763433` | 0 s | `md70` | PASS |
|
||||
| LZ4 | `3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880` | 5 s | `md71` | PASS |
|
||||
| LZMA | `ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461` | 2 s | `md72` | PASS |
|
||||
|
||||
The LZMA case hashed the complete file. No timeout, mount failure, hash mismatch,
|
||||
unmount failure, or md detach failure occurred.
|
||||
|
||||
## Kernel Messages and Cleanup
|
||||
|
||||
The runner captured `dmesg` before loading the module and after all smoke cases.
|
||||
The delta contained no EROFS error, decompression failure, panic, or assertion;
|
||||
the suspect-output file is empty.
|
||||
|
||||
Cleanup evidence records:
|
||||
|
||||
```text
|
||||
qemu_stopped=1
|
||||
port_released=1
|
||||
overlay_removed=1
|
||||
base_mode_after=444
|
||||
base_sha_after=67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef
|
||||
guard_unchanged_and_reachable=1
|
||||
body_rc=0
|
||||
cleanup_rc=0
|
||||
```
|
||||
|
||||
The test owned only port `10044`, its QEMU PID, its ControlMaster PID, and its
|
||||
overlay. All were closed or removed. The permanent base image was never booted
|
||||
directly and retained mode `0444` and its original SHA256. The retained guard VM
|
||||
PID `26318` kept start time `1102996924`, an identical command line, and a
|
||||
reachable forwarded SSH port at `9222`.
|
||||
|
||||
## Feature-Test Decision
|
||||
|
||||
No feature test and no `test_all.py` run was performed.
|
||||
|
||||
That decision is appropriate for the included Pre11 scope because:
|
||||
|
||||
- Batch A changed only private identifiers;
|
||||
- Batch B removed proven dead state and reordered designated VOP initializers
|
||||
without changing their mappings;
|
||||
- Batch C mechanically moved parser statements while retaining inputs, outputs,
|
||||
writes, error order, and ownership;
|
||||
- Batch D was a byte-identical file rename;
|
||||
- Batch E consolidated one caller-owned cleanup action and removed checks that
|
||||
cannot be reached after `M_WAITOK` allocation.
|
||||
|
||||
Static equivalence review plus the FreeBSD build and plain/LZ4/LZMA smoke is
|
||||
sufficient evidence for these changes. It is not sufficient for the deferred
|
||||
behavior changes below, and this report does not claim otherwise.
|
||||
|
||||
## Deferred Behavior and Required Targeted Tests
|
||||
|
||||
### Non-directory root
|
||||
|
||||
The current root path does not add a new rejection for a root NID that resolves
|
||||
to a non-directory vnode. A future fix requires a purpose-built image and checks
|
||||
for mount errno, vnode release, mount error text, and complete cleanup.
|
||||
|
||||
### Zero-length internal run
|
||||
|
||||
The uncompressed UIO reader's existing `run_len == 0` behavior was not changed.
|
||||
A future fix requires a corrupt mapping fixture that reaches a zero-length run
|
||||
while the request remains inside the file, with exact comparison to the
|
||||
contiguous-buffer path and expected `EINTEGRITY`.
|
||||
|
||||
### Header-only xattr
|
||||
|
||||
The existing behavior for an ibody containing only the xattr header was not
|
||||
changed. Targeted coverage must distinguish zero and nonzero shared counts,
|
||||
name filters, get/list results, ACL mode fallback, and corruption results.
|
||||
|
||||
### Duplicate or missing device slots
|
||||
|
||||
`device.N` slot parsing behavior and diagnostics were not changed. Future tests
|
||||
must cover duplicate, out-of-order, missing, excessive, and malformed slots,
|
||||
flat and non-flat device tables, exact errno and mount error text, and GEOM
|
||||
cleanup.
|
||||
|
||||
### `insmntque()` race closure
|
||||
|
||||
The earlier ownership fix remains accepted by static lifecycle review but is
|
||||
not runtime-closed by ordinary smoke. A dedicated mount/unmount or forced
|
||||
unmount race must stress vnode creation and inspect panic, use-after-free, lock,
|
||||
reference, and cleanup behavior.
|
||||
|
||||
### Explicit mapped extent fixtures
|
||||
|
||||
Positive payload fixtures are still unavailable for explicit mapped extent
|
||||
records of 4, 8, 16, and 32 bytes. No restructuring or coverage claim should be
|
||||
made until validated mappings and file hashes exist.
|
||||
|
||||
### `vnode_create_vobject()` errno
|
||||
|
||||
Pre11 intentionally retains the current conversion of a nonzero
|
||||
`vnode_create_vobject()` result to `ENOMEM`. Direct propagation is a visible
|
||||
behavior change and requires controlled pager failure or fault injection that
|
||||
verifies the caller-visible errno and vnode state.
|
||||
|
||||
## Final Conclusion
|
||||
|
||||
Pre11 completed all five narrowed maintenance batches, passed independent
|
||||
static review, built successfully as a FreeBSD KLD, and passed the required
|
||||
plain, LZ4, and full-file LZMA smoke. The first smoke attempt was correctly
|
||||
classified as an infrastructure failure before DUT transfer or build; the
|
||||
corrected retry provides the runtime evidence.
|
||||
|
||||
Pre11 improves cross-repository maintainability without replacing native
|
||||
FreeBSD vnode, GEOM, UIO, pager, ACL, or synchronous decompression contracts.
|
||||
Full feature validation remains outside this release and must not be inferred
|
||||
from the targeted smoke result.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Pre12 Baseline
|
||||
|
||||
`repo-pre-12` was created as an exact snapshot copy of `repo-pre-11` before this document was added.
|
||||
|
||||
- Source commit: `88fc67742e6c173e14538d4fcd556a45a385c2c9`
|
||||
- Source tree (`repo-pre-11`): `5b8c637bcb535f330d894f30660bb5e65db70048`
|
||||
- Copied tree before this document (`repo-pre-12`): `5b8c637bcb535f330d894f30660bb5e65db70048`
|
||||
- Source `src` tree: `c4aac4d69cb25a4b049239d0c1f422dcb89465d6`
|
||||
- Copied `src` tree: `c4aac4d69cb25a4b049239d0c1f422dcb89465d6`
|
||||
|
||||
Copy verification used a recursive comparison that preserved and checked file modes and symbolic links. The complete tree IDs matched before this document was added. Adding this document does not modify the copied `src` tree.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Pre12 Batch 01
|
||||
|
||||
This batch aligns the planned in-memory NID, block-number, and byte-offset
|
||||
declarations with the existing `erofs_nid_t`, `erofs_blk_t`, and
|
||||
`erofs_off_t` aliases.
|
||||
|
||||
The source whitelist was limited to eight fields in `internal.h`, the
|
||||
`erofs_iloc`, `erofs_nid_is_valid`, `erofs_read_inode`, and `erofs_vfs_hash`
|
||||
declarations and definitions, and the byte-offset parameters of
|
||||
`erofs_bread`, `erofs_read_physical`, and `erofs_read_metadata`.
|
||||
|
||||
All three aliases are direct `uint64_t` typedefs. Static assertions confirmed
|
||||
that each is an unsigned, 8-byte type with the same alignment and exact C type
|
||||
compatibility as `uint64_t`. Consequently every replaced field has identical
|
||||
size and alignment, so both structure sizes, alignments, field order, and all
|
||||
target `offsetof` values are unchanged. Function parameter and return ABI
|
||||
representations are also unchanged, and the vnode hash still consumes the
|
||||
same complete 8-byte NID object.
|
||||
|
||||
The source diff is limited to the planned fields, function declarations and
|
||||
definitions, and necessary local declaration splits. No expressions, field
|
||||
order, on-disk types, control flow, error handling, or formatting outside
|
||||
those declarations changed.
|
||||
|
||||
Validation used exact declaration inventory checks, token-diff inspection,
|
||||
declaration/definition signature comparison, arithmetic and hash review,
|
||||
compile-time type assertions, and `git diff --check`. No planned point was
|
||||
skipped and no out-of-scope candidate was changed. No build, QEMU, smoke,
|
||||
feature, or other dynamic test was run.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Pre12 Batch 02
|
||||
|
||||
This batch replaces exactly three potentially unaligned typed loads with the
|
||||
FreeBSD little-endian byte decoders planned for Pre12.
|
||||
|
||||
- `xattr.c`: `hdrbuf` contains two raw metadata bytes returned by
|
||||
`erofs_xattr_read_backing(..., sizeof(raw_len), ...)`; `le16dec(hdrbuf)`
|
||||
decodes the prefix-record length.
|
||||
- `inode.c`: `buf` contains at least one complete 32-byte compact on-disk inode
|
||||
returned by `erofs_read_metadata`; its first two bytes are the little-endian
|
||||
`i_format` field decoded by `le16dec(buf)`.
|
||||
- `data.c`: the non-indexes branch sets `entry_size` to
|
||||
`EROFS_BLOCK_MAP_ENTRY_SIZE == sizeof(__le32) == 4`; `idx` points to those
|
||||
four raw block-map bytes and `le32dec(idx)` decodes the block address.
|
||||
|
||||
For bytes `b0..b3`, both old expressions and the new helpers produce
|
||||
`b0 | b1 << 8` or `b0 | b1 << 8 | b2 << 16 | b3 << 24`. On a little-endian
|
||||
host the typed load already has that value; on a big-endian host `leXXtoh`
|
||||
byte-swaps the typed value to that same formula. The helpers preserve this
|
||||
result while avoiding any alignment requirement.
|
||||
|
||||
`xattr.c` and `data.c` receive the helpers through `internal.h` to
|
||||
`erofs_fs.h` to `<sys/endian.h>`; `inode.c` also includes `<sys/endian.h>`
|
||||
directly. Existing `le16dec` and `le32dec` consumers confirm the established
|
||||
include convention. Error checks, branches, value ranges, and buffer release
|
||||
ordering are unchanged. No point was skipped and no other endian read was
|
||||
changed.
|
||||
|
||||
Validation used exact-expression counts, buffer-source and length inspection,
|
||||
symbolic endian equivalence, source-diff inspection, and `git diff --check`.
|
||||
No build, QEMU, smoke, feature, or other dynamic test was run.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Pre12 Batch 03: POSIX ACL mode helper
|
||||
|
||||
## Change
|
||||
|
||||
- In `src/xattr.c`, `erofs_acl_from_mode` now obtains the owner, group, and
|
||||
other permissions with `acl_posix1e_mode_to_perm`.
|
||||
- The helper tags are `ACL_USER_OBJ`, `ACL_GROUP_OBJ`, and `ACL_OTHER`, matching
|
||||
the adjacent `ae_tag` assignments.
|
||||
- No other function lines, ACL entry ordering, `acl_cnt`, IDs, default ACL
|
||||
handling, fallback behavior, flags, errno behavior, or control flow changed.
|
||||
|
||||
## Helper confirmation
|
||||
|
||||
- The local FreeBSD header `sys/sys/acl.h` declares
|
||||
`acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)` for kernel consumers.
|
||||
- The local FreeBSD implementation in `sys/kern/subr_acl_posix1e.c` maps
|
||||
`ACL_USER_OBJ` from `S_IRWXU`, `ACL_GROUP_OBJ` from `S_IRWXG`, and
|
||||
`ACL_OTHER` from `S_IRWXO`, returning the corresponding POSIX ACL read,
|
||||
write, and execute permission bits.
|
||||
- `src/xattr.c` already includes `<sys/acl.h>`; no include change was needed.
|
||||
|
||||
## Exhaustive equivalence
|
||||
|
||||
A temporary standalone C program reproduced the local FreeBSD helper logic and
|
||||
compared it with the three replaced expressions for every permission mode from
|
||||
`0000` through `0777`:
|
||||
|
||||
```text
|
||||
equivalent=1536/1536 modes=512 tags=3 mismatches=0
|
||||
temporary_cleanup=ok
|
||||
```
|
||||
|
||||
This covers 512 modes for each of the three tags. The temporary source and
|
||||
executable were deleted and are not part of the repository.
|
||||
|
||||
## Static validation
|
||||
|
||||
- The `erofs_acl_from_mode` function is line-for-line unchanged except for the
|
||||
three `ae_perm` expressions.
|
||||
- The source diff changes only those three expressions; this document is the
|
||||
only added file.
|
||||
- `git diff --check` and `git diff --cached --check` completed without errors.
|
||||
- Before commit, both unstaged status and staged status contained only
|
||||
`src/xattr.c` and `docs/pre12-batch-03.md` under `repo-pre-12`.
|
||||
|
||||
## Tests not run
|
||||
|
||||
Per the Batch 03 execution constraints, no project build, QEMU run, smoke test,
|
||||
or feature test was run.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Pre12 Batch 04: Private compression header
|
||||
|
||||
## Change
|
||||
|
||||
- Added `src/compress.h` for the decompressor request, descriptor, and backend
|
||||
private declarations previously located in `src/internal.h`.
|
||||
- Added the header only to `decompressor.c` and the LZ4, LZMA, Deflate, and
|
||||
ZSTD backend translation units.
|
||||
- Kept the runtime compression enum, `z_erofs_parse_cfgs`, and the public
|
||||
`z_erofs_decompress` declaration in `src/internal.h`.
|
||||
- Preserved every migrated declaration signature and storage duration. No
|
||||
function body, callback, conditional compilation block, errno path, or
|
||||
buffer ownership changed.
|
||||
|
||||
## Static validation
|
||||
|
||||
- The `compress.h` consumer set is exactly the five planned decompressor
|
||||
translation units; `super.c`, `zdata.c`, and all other public callers still
|
||||
include only `internal.h`.
|
||||
- The include graph is acyclic: `compress.h` includes `internal.h`, while
|
||||
`internal.h` does not include `compress.h`.
|
||||
- Exact searches found one definition of each migrated structure and one
|
||||
declaration of each migrated backend function. The old declarations are
|
||||
absent from `internal.h`.
|
||||
- The new header contains no Linux page, folio, bio, workqueue, XArray,
|
||||
shrinker, compatibility, or related runtime declarations.
|
||||
- Source diff inspection and declaration normalization confirmed that this is
|
||||
a declaration-only move plus the five include additions.
|
||||
- `git diff --check` and `git diff --cached --check` completed without errors.
|
||||
|
||||
## Tests not run
|
||||
|
||||
Per the execution constraints, no build, QEMU run, smoke test, feature test,
|
||||
or other dynamic test was run. The planned `WITH_ZSTDIO=0` and
|
||||
`WITH_ZSTDIO=1` KLD builds remain required during final validation.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Pre12 Batch 05: ZSTD window lower bound
|
||||
|
||||
## Change
|
||||
|
||||
- Removed only the `rq->em->zstd_windowlog + 10 < 10` subcondition from
|
||||
`z_erofs_zstd_decompress`.
|
||||
- Preserved the `> 20` upper bound, the `outputsize == 0` check, every
|
||||
`return (-1)`, all ZSTD calls, resource release, and the complete disabled
|
||||
`#else` stub.
|
||||
- Did not change ZSTD configuration parsing, accepted configuration range,
|
||||
conditional compilation, errno behavior, or control flow after the guard.
|
||||
|
||||
## Static proof
|
||||
|
||||
- `struct erofs_mount.zstd_windowlog` is `uint8_t`, so integer promotion gives
|
||||
a value in the range 0 through 255.
|
||||
- Adding 10 therefore produces a minimum value of 10; comparison with `< 10`
|
||||
is unreachable for every representable field value.
|
||||
- `z_erofs_load_zstd_config` still rejects `windowlog > 10`, so configured
|
||||
mount values and the remaining decompression upper-bound behavior are
|
||||
unchanged.
|
||||
- Normalized function comparison confirms that the only removed logical
|
||||
tokens are the single unreachable lower-bound subcondition and its `||`.
|
||||
- `git diff --check` and `git diff --cached --check` completed without errors.
|
||||
|
||||
## Tests not run
|
||||
|
||||
Per the execution constraints, no build, QEMU run, smoke test, feature test,
|
||||
or other dynamic test was run. A FreeBSD KLD build with `WITH_ZSTDIO=1`
|
||||
remains mandatory during final validation so this enabled function body is
|
||||
compiled.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Pre-12 Batch 06: codec descriptor ownership
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Scope
|
||||
|
||||
- Moved the LZMA, DEFLATE, and ZSTD descriptors into their backend source
|
||||
files.
|
||||
- Made their backend-only config, decompress, and availability helpers
|
||||
`static`.
|
||||
- Kept the LZ4 config loader and descriptor, plus the SHIFTED and INTERLACED
|
||||
descriptors and transform, in `src/decompressor.c`.
|
||||
- Replaced the central descriptor object array with the descriptor pointer
|
||||
table `z_erofs_decomp`.
|
||||
- Reduced `src/compress.h` to the three backend descriptor declarations and
|
||||
the LZ4 decompress prototype needed by the central descriptor.
|
||||
|
||||
## Descriptor tuples
|
||||
|
||||
The normalized tuples are unchanged before and after this batch:
|
||||
|
||||
| Index | Name | Config callback | Decompress callback | Compile condition |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `Z_EROFS_COMPRESSION_LZ4` | `lz4` | `z_erofs_load_lz4_config` | `z_erofs_lz4_decompress` | always |
|
||||
| `Z_EROFS_COMPRESSION_LZMA` | `lzma` | `z_erofs_load_lzma_config` | `z_erofs_lzma_decompress` | always |
|
||||
| `Z_EROFS_COMPRESSION_DEFLATE` | `deflate` | `z_erofs_load_deflate_config` | `z_erofs_deflate_decompress` | always |
|
||||
| `Z_EROFS_COMPRESSION_ZSTD` | `zstd` | `z_erofs_load_zstd_config` | `z_erofs_zstd_decompress` | descriptor and config always; decompress implementation selected by `ZSTDIO` |
|
||||
| `Z_EROFS_COMPRESSION_SHIFTED` | `shifted` | `NULL` | `z_erofs_transform_plain` | always |
|
||||
| `Z_EROFS_COMPRESSION_INTERLACED` | `interlaced` | `NULL` | `z_erofs_transform_plain` | always |
|
||||
|
||||
## Static validation
|
||||
|
||||
- Confirmed one declaration and one definition for each backend descriptor;
|
||||
the only additional occurrence is its central pointer-table entry.
|
||||
- Confirmed the LZMA and DEFLATE config/decompress helpers have no external
|
||||
consumers and are now `static` in their backends.
|
||||
- Confirmed the ZSTD config/decompress/availability helpers have no external
|
||||
consumers and are now `static`; the two decompress definitions are mutually
|
||||
exclusive under `#ifdef ZSTDIO`.
|
||||
- Confirmed `z_erofs_decomp` explicitly fills all six runtime indices in the
|
||||
original order. Decompression retains the array-length bound, rejects a
|
||||
null table entry, and rejects a null decompress callback with
|
||||
`EOPNOTSUPP`. Config parsing retains the existing compression-config loop
|
||||
bound and treats a null entry or null config callback as `EOPNOTSUPP` before
|
||||
releasing the config buffer on the existing path.
|
||||
- Confirmed the `WITH_ZSTDIO=0` static conditional path remained valid;
|
||||
actual build deferred to final validation. Without `ZSTDIO`, the path
|
||||
keeps the descriptor non-null, reports the existing mount error and
|
||||
`EOPNOTSUPP` from config, and selects the decompress stub returning `-1`.
|
||||
- Confirmed `WITH_ZSTDIO=1` adds `-DZSTDIO`, keeps the same descriptor and
|
||||
config callback, and selects the existing ZSTD implementation with its
|
||||
resource-release and error paths unchanged.
|
||||
- `git diff --check` and `git diff --cached --check` were required for this
|
||||
batch.
|
||||
|
||||
## Deferred validation
|
||||
|
||||
No build, QEMU, smoke, feature, or other dynamic validation was run for this
|
||||
batch. Follow-up validation must build the FreeBSD KLD with both
|
||||
`WITH_ZSTDIO=0` and `WITH_ZSTDIO=1`.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Pre-12 Batch 07: exact macro alignment
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Scope
|
||||
|
||||
- Renamed only `EROFS_ALL_SUPPORTED_INCOMPAT` to the Linux name
|
||||
`EROFS_ALL_FEATURE_INCOMPAT` in its comment, definition, and sole source
|
||||
use.
|
||||
- Deleted only the zero-consumer compatibility alias
|
||||
`EROFS_CHUNK_FORMAT_INDEXES_FLAG`.
|
||||
|
||||
## Static proof
|
||||
|
||||
- Before the edit, the target tree had exactly three source occurrences of
|
||||
`EROFS_ALL_SUPPORTED_INCOMPAT`: its comment and definition in
|
||||
`src/erofs_fs.h`, and the `src/super.c` unsupported-feature calculation.
|
||||
The two additional target-tree matches were historical review prose, not
|
||||
source or build consumers.
|
||||
- After the edit, the old source name has zero occurrences and
|
||||
`EROFS_ALL_FEATURE_INCOMPAT` has exactly the same comment, definition, and
|
||||
sole `src/super.c` use.
|
||||
- The macro continuation expression and its feature-bit operands are
|
||||
unchanged. The unsupported calculation changes only the macro token.
|
||||
- A tracked-tree exact-symbol search found
|
||||
`EROFS_CHUNK_FORMAT_INDEXES_FLAG` only as identical definitions in retained
|
||||
repository snapshots. The target tree had exactly one occurrence: the
|
||||
definition being deleted.
|
||||
- Exact searches of target-tree Makefiles, scripts, documentation, text
|
||||
interfaces, and preprocessor `-D` flags found no consumer of the deleted
|
||||
alias. Existing code continues to use `EROFS_CHUNK_FORMAT_INDEXES`;
|
||||
`EROFS_CHUNK_FORMAT_ALL` and chunk decoding are unchanged.
|
||||
- `git diff --check` and `git diff --cached --check` were required for this
|
||||
batch.
|
||||
|
||||
## Deferred validation
|
||||
|
||||
No build, QEMU, smoke, feature, or other dynamic validation was run for this
|
||||
batch. The final KLD and Plain/LZ4/LZMA validation remains deferred.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Pre-12 Batch 08: xattr helper order
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Scope
|
||||
|
||||
- Moved the complete `static erofs_listxattr_foreach` function block to
|
||||
immediately precede `erofs_getxattr_foreach` in `src/xattr.c`.
|
||||
- Made no changes to either function body, signature, visibility, callers, or
|
||||
conditional-compilation context.
|
||||
|
||||
## Static proof
|
||||
|
||||
- The exact function block from `static int` through its closing brace had
|
||||
SHA-256 `0541c211f78a19f39caeebdafe73bdd0a7064e996686a7b45c9c651160ed98ae`
|
||||
before and after the move.
|
||||
- The target remains one `static` definition with two call sites, in the
|
||||
inline and shared xattr iterators.
|
||||
- `erofs_getxattr_foreach` remains one definition with the same two call
|
||||
sites; its complete block is unchanged.
|
||||
- Both helpers remain in the same unconditional compilation region after
|
||||
`struct erofs_xattr_iter` and before the iterator functions, so no forward
|
||||
declaration or conditional boundary was introduced.
|
||||
- The source diff is a pure block move; adjacent xattr and ACL logic is
|
||||
unchanged.
|
||||
- `git diff --check` and `git diff --cached --check` were required for this
|
||||
batch.
|
||||
|
||||
## Deferred validation
|
||||
|
||||
No build, QEMU, smoke, feature, or other dynamic validation was run for this
|
||||
batch. Final KLD and Plain/LZ4/LZMA validation remains deferred.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Pre-12 Batch 09: compression header responsibility
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Scope
|
||||
|
||||
- Removed the direct `internal.h` include from `decompressor.c` and the four
|
||||
`decompressor_*.c` backend consumers that already include `compress.h`.
|
||||
- Made no declaration, definition, function, storage-duration, or public API
|
||||
changes.
|
||||
|
||||
## Candidate source
|
||||
|
||||
Batch 04 created `compress.h` with a direct `internal.h` include and added
|
||||
`compress.h` to these five translation units while retaining their direct
|
||||
`internal.h` includes. Batch 06 then made LZMA, DEFLATE, and ZSTD backend
|
||||
functions private and exposed only their descriptor objects through
|
||||
`compress.h`. This left exactly five duplicate include edges attributable to
|
||||
Batches 04/06.
|
||||
|
||||
## Static proof
|
||||
|
||||
- `compress.h` remains the sole owner of `z_erofs_decompress_req`,
|
||||
`z_erofs_decompressor`, the LZ4 decompressor prototype, and the three
|
||||
backend descriptor declarations.
|
||||
- `internal.h` remains the sole public owner of `z_erofs_decompress` and
|
||||
`z_erofs_parse_cfgs`; it does not include `compress.h`.
|
||||
- The include graph remains acyclic: each affected translation unit includes
|
||||
`compress.h`, and `compress.h` includes `internal.h`, which includes only
|
||||
`erofs_fs.h` among project headers.
|
||||
- Each affected consumer therefore still sees the same complete request,
|
||||
descriptor, mount, map, and superblock types through one guarded include
|
||||
path. No backend prototype or descriptor declaration is duplicated between
|
||||
`internal.h` and `compress.h`.
|
||||
- The source diff removes exactly one `#include "internal.h"` line from each
|
||||
of five authorized files and changes no other token.
|
||||
- `git diff --check` and `git diff --cached --check` were required for this
|
||||
batch.
|
||||
|
||||
## Deferred validation
|
||||
|
||||
No build, QEMU, smoke, feature, or other dynamic validation was run under the
|
||||
execution constraint. The required FreeBSD KLD `WITH_ZSTDIO=0/1` matrix and
|
||||
final Plain/LZ4/LZMA validation remain deferred.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Pre-12 Batch 10: Makefile readability review
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Result
|
||||
|
||||
No-op. `src/Makefile` was reviewed after Batches 04, 06, and 09, but no
|
||||
non-redundant comment or blank-line grouping with clear maintenance value was
|
||||
identified.
|
||||
|
||||
## Static proof
|
||||
|
||||
- The `SRCS` list already keeps the core filesystem sources, mapping and data
|
||||
sources, and `decompressor_*.c` sources in readable contiguous regions.
|
||||
- Adding labels would repeat names already visible in the short source list.
|
||||
- `src/Makefile` is byte-for-byte unchanged.
|
||||
- The `SRCS` elements, order, duplicate counts, `WITH_ZSTDIO` condition,
|
||||
per-file CFLAGS, target, and `.include` line are unchanged.
|
||||
- `git diff --check` and `git diff --cached --check` were required for this
|
||||
documentation-only closeout.
|
||||
|
||||
## Validation
|
||||
|
||||
No build, QEMU, smoke, or feature test was run for this no-op review.
|
||||
@@ -0,0 +1,229 @@
|
||||
# Pre12 Final Report
|
||||
|
||||
Date: 2026-08-13
|
||||
|
||||
## Conclusion and scope
|
||||
|
||||
Pre12 is complete for its deliberately limited scope. The final result is
|
||||
**PASS** for the planned static review, both FreeBSD KLD build configurations,
|
||||
KLD load/status/unload, and the ordinary Plain/LZ4/LZMA QEMU smoke cases.
|
||||
|
||||
This PASS is not a claim of complete EROFS feature validation. No feature
|
||||
test, `test_all.py`, new fixture, ZSTD data test, DEFLATE data test, ACL runtime
|
||||
test, explicit-extent test, or multi-device test was run. The included changes
|
||||
were selected as low-side-effect maintenance work and did not require a full
|
||||
feature suite after their static proofs and final build/smoke matrix. Deferred
|
||||
behavior work remains unresolved and is listed below.
|
||||
|
||||
The validated device-under-test identity is:
|
||||
|
||||
| Identity | Value |
|
||||
| --- | --- |
|
||||
| Commit | `a55e42a117e504f6ece49be3c2a2d81603031ea3` |
|
||||
| `repo-pre-12` tree | `9161671bd0e855faa52c37e24fe8efcd6ddd71e0` |
|
||||
| `repo-pre-12/src` tree | `d63c45c7872dcf9dd84007c8883cf9fbe0f9467d` |
|
||||
| Source archive SHA-256 | `bb7e7f0383be29102475575e130e0b19a48452d20520c94059dc6ef128d0c7ce` |
|
||||
|
||||
## Goals
|
||||
|
||||
Pre12 continued the staged effort to reduce unnecessary maintenance
|
||||
differences from Linux EROFS without importing Linux-only memory, I/O, device,
|
||||
or concurrency models into FreeBSD. Its concrete scope was nine core batches
|
||||
and one conditional maintenance closeout:
|
||||
|
||||
1. Use existing semantic scalar aliases where their width and signedness are
|
||||
exactly equivalent.
|
||||
2. Use FreeBSD unaligned little-endian readers for raw on-disk bytes.
|
||||
3. Use the FreeBSD POSIX.1e ACL mode conversion facility.
|
||||
4. Introduce a Linux-comparable private compression header.
|
||||
5. Remove an unreachable ZSTD lower-bound condition.
|
||||
6. Align codec descriptor ownership while preserving FreeBSD behavior.
|
||||
7. Align exact macro vocabulary and remove one zero-consumer alias.
|
||||
8. Align one xattr helper's file order through a byte-identical block move.
|
||||
9. Remove include duplication introduced by the compression-header work.
|
||||
10. Review Makefile readability and make no change when no useful grouping
|
||||
was found.
|
||||
|
||||
The work explicitly excluded broad file reordering, catch-all style cleanup,
|
||||
Linux page/folio/bio/workqueue infrastructure, and behavior changes requiring
|
||||
specialized feature fixtures.
|
||||
|
||||
## Batch results
|
||||
|
||||
| Batch | Commit | Result and summary |
|
||||
| --- | --- | --- |
|
||||
| 01 | `bb28c47bdf4de777febde05ebb333c420ea1e9b9` | Replaced the planned NID, block-number, and byte-offset declarations with existing equal-width unsigned `erofs_nid_t`, `erofs_blk_t`, and `erofs_off_t` aliases. Field order, layout, ABI width, expressions, on-disk types, and control flow were unchanged. |
|
||||
| 02 | `76a655788538f2270626cff1ca91b8c47700d536` | Replaced exactly three potentially unaligned typed loads with `le16dec`/`le32dec` in xattr, inode, and block-map decoding. |
|
||||
| 03 | `35bde15f5242f84a6343cc9e96519fcce4eeca90` | Replaced three manual ACL mode shifts with `acl_posix1e_mode_to_perm` for owner, group, and other entries. |
|
||||
| 04 | `b591751f90e62bc0ec54d3f34c724f698c99813d` | Added `src/compress.h` for private decompressor request, descriptor, and backend declarations; public entry points and runtime enum remained in `internal.h`. |
|
||||
| 05 | `aaa3c5db40745ee558e6fcf6375d60e044217df9` | Removed only the unreachable `zstd_windowlog + 10 < 10` subcondition; the upper bound, zero-output check, disabled stub, errno behavior, and resource handling remained unchanged. |
|
||||
| 06 | `6748d58f7e15927321f44a83d81a6c697c1185ae` | Moved LZMA, DEFLATE, and ZSTD descriptors into their backends, kept LZ4 and plain transforms central, and changed the central descriptor table to the pointer table `z_erofs_decomp`. All six normalized descriptor tuples and indices remained unchanged. |
|
||||
| 07 | `292da21bd9288cac4a8b280bb67970c8b9058550` | Renamed `EROFS_ALL_SUPPORTED_INCOMPAT` to Linux's `EROFS_ALL_FEATURE_INCOMPAT` at its definition and sole source use, and removed zero-consumer `EROFS_CHUNK_FORMAT_INDEXES_FLAG`. |
|
||||
| 08 | `0be5642d917104f1904bcfadaea803c9845c7a5c` | Moved the complete `erofs_listxattr_foreach` static function block before `erofs_getxattr_foreach`; the block SHA-256 remained `0541c211f78a19f39caeebdafe73bdd0a7064e996686a7b45c9c651160ed98ae`. |
|
||||
| 09 | `e5315489eb5ed08884d5d5f2645264067e36838e` | Removed five direct `internal.h` includes made redundant by `compress.h`; declaration visibility and the acyclic include graph were preserved. |
|
||||
| 10 | `a55e42a117e504f6ece49be3c2a2d81603031ea3` | Conditional Makefile readability closeout: honest no-op. The source list and Makefile remained byte-for-byte unchanged because no non-redundant grouping comment was justified. |
|
||||
|
||||
Batch 10 is not counted among the nine core source workflows. Batch 09 did
|
||||
produce a precise cleanup diff, while Batch 10 records the required review
|
||||
without manufacturing source churn.
|
||||
|
||||
## Static review
|
||||
|
||||
The final static review found no source-blocking issue. In particular, it did
|
||||
not find a regression in declaration/definition matching, include ownership or
|
||||
graph shape, descriptor indices and callback ownership, errno paths, resource
|
||||
release, in-memory ABI/layout, endian decoding, ACL construction, macro values,
|
||||
or the byte-identical xattr function move.
|
||||
|
||||
The important proofs were:
|
||||
|
||||
- The three semantic scalar aliases are direct unsigned 64-bit aliases; the
|
||||
approved substitutions preserve size, alignment, signedness, structure
|
||||
layout, parameter representation, and arithmetic width.
|
||||
- The three `le16dec`/`le32dec` inputs are raw little-endian disk bytes of the
|
||||
required length; the decoded values are equivalent while avoiding typed
|
||||
unaligned loads.
|
||||
- ACL owner/group/other conversion was exhaustively compared across modes
|
||||
`0000` through `0777`: `1536/1536` tag/mode combinations were equivalent,
|
||||
with zero mismatches.
|
||||
- The compression include graph remained acyclic and each migrated or private
|
||||
symbol retained one authoritative declaration/definition relationship.
|
||||
- The six codec descriptor tuples, indices, names, config callbacks,
|
||||
decompress callbacks, and ZSTD conditional ownership remained equivalent.
|
||||
- The removed ZSTD lower bound is unreachable because the field is `uint8_t`;
|
||||
its promoted value plus 10 cannot be less than 10.
|
||||
- Macro expressions and values were unchanged, and the deleted chunk-format
|
||||
alias had no source, build, documentation-interface, or preprocessor
|
||||
consumer in the target tree.
|
||||
- The moved xattr function block retained its exact SHA-256 and conditional
|
||||
context.
|
||||
|
||||
The Batch 06 record originally used wording that could imply an actual
|
||||
`WITH_ZSTDIO=0` build had already occurred during that batch. It has been
|
||||
corrected to state that only the static conditional path was validated then.
|
||||
Final validation subsequently built both configurations successfully.
|
||||
|
||||
## KLD build matrix
|
||||
|
||||
The valid final run used FreeBSD `15.0-RELEASE-p8`, amd64, with `/usr/src/sys`
|
||||
and the in-tree FreeBSD ZSTD headers present. The extracted source archive
|
||||
matched SHA-256
|
||||
`bb7e7f0383be29102475575e130e0b19a48452d20520c94059dc6ef128d0c7ce`.
|
||||
|
||||
For each configuration, the guest executed:
|
||||
|
||||
```sh
|
||||
timeout -k 10s 120s make "WITH_ZSTDIO=<0-or-1>" clean
|
||||
timeout -k 10s 600s make "WITH_ZSTDIO=<0-or-1>"
|
||||
```
|
||||
|
||||
| Configuration | Clean exit | Build exit | Module SHA-256 |
|
||||
| --- | ---: | ---: | --- |
|
||||
| `WITH_ZSTDIO=0` | 0 | 0 | `96dc276c6c3f68943e68a144cc2ea138ffc215b62c7392cad9688ec45c9fc2fb` |
|
||||
| `WITH_ZSTDIO=1` | 0 | 0 | `4d879c0b7ebc653e915a3e41863f74d6d5b5f18aa81c5178579368048d1b6ee3` |
|
||||
|
||||
The enabled build compiled `decompressor_zstd.c` with `-DZSTDIO` and linked
|
||||
`erofs.ko`. These builds prove both compile-time configurations close and link;
|
||||
they do not prove ZSTD or DEFLATE data-path correctness.
|
||||
|
||||
## KLD and smoke results
|
||||
|
||||
The valid run loaded the `WITH_ZSTDIO=1` artifact under the standard module
|
||||
name `erofs.ko`.
|
||||
|
||||
| Check | Result |
|
||||
| --- | --- |
|
||||
| `kldload` | exit 0 |
|
||||
| `kldstat -n erofs.ko` | present as `erofs.ko`, module id 5 |
|
||||
| Loaded module SHA-256 | `4d879c0b7ebc653e915a3e41863f74d6d5b5f18aa81c5178579368048d1b6ee3` |
|
||||
| `kldunload erofs.ko` | exit 0 |
|
||||
| Post-unload `kldstat` | module absent, as expected |
|
||||
|
||||
All ordinary read cases matched their complete expected hashes:
|
||||
|
||||
| Case | Exit | Expected SHA-256 | Actual SHA-256 | Elapsed |
|
||||
| --- | ---: | --- | --- | ---: |
|
||||
| Plain | 0 | `056f8f7585667dc695e2edf936deaf84cfee0f88671ba6cd5be22ce890763433` | `056f8f7585667dc695e2edf936deaf84cfee0f88671ba6cd5be22ce890763433` | 593 ms |
|
||||
| LZ4 | 0 | `3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880` | `3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880` | 6822 ms |
|
||||
| LZMA | 0 | `ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461` | `ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461` | 3418 ms |
|
||||
|
||||
The dmesg delta was zero bytes and the suspect-filter output was zero bytes.
|
||||
No new panic, trap, or EROFS error was observed.
|
||||
|
||||
## Evidence and invalid attempts
|
||||
|
||||
The only final valid evidence directory is:
|
||||
|
||||
```text
|
||||
/work/tests-dev/temp/pre12-smoke-direct-20260813T165639Z/
|
||||
```
|
||||
|
||||
Its `final-summary.txt`, guest build logs, module hashes, case records, dmesg
|
||||
files, and cleanup record form the accepted evidence set.
|
||||
|
||||
Two earlier infrastructure attempts are explicitly invalid and contribute no
|
||||
source result and no test pass:
|
||||
|
||||
1. `/work/tests-dev/temp/pre12-build-20260813T154900Z/` is **INFRA-FAIL**.
|
||||
The SSH password expanded to an empty string, so there were zero successful
|
||||
SSH sessions and neither build began. Its QEMU and temporary resources were
|
||||
cleaned. This is neither a DUT failure nor a test success.
|
||||
2. `/work/tests-dev/temp/pre12-final-smoke-20260813T160957Z/` stopped while
|
||||
redundantly hashing the 16 GB base image. Five nested Codex CLI sessions
|
||||
were discovered and all were terminated or had exited; no QEMU, SSH,
|
||||
guest build, KLD action, or smoke case started. Its partial files are not
|
||||
test evidence and it is neither a DUT failure nor a test success.
|
||||
|
||||
The final accepted run was performed by a single direct execution layer and
|
||||
did not start a nested agent or Codex process.
|
||||
|
||||
One intermediate runner revision attempted to query KLD using the renamed
|
||||
artifact filename rather than the module's standard name. That was a
|
||||
test-period runner issue, not a DUT issue. Only the temporary runner copy under
|
||||
`tests-dev/temp` was corrected: the successful `WITH_ZSTDIO=1` artifact was
|
||||
copied to `erofs.ko`, then the complete KLD and Plain/LZ4/LZMA sequence was
|
||||
rerun. No `repo-pre-12` source or build file was modified to make the test
|
||||
pass.
|
||||
|
||||
## Cleanup and repository state
|
||||
|
||||
The accepted run completed cleanup successfully:
|
||||
|
||||
- Owned QEMU stopped.
|
||||
- SSH ControlMaster stopped.
|
||||
- Test port `10048` released.
|
||||
- Test overlay removed.
|
||||
- Guest test mounts and `md70`/`md71`/`md72` devices were removed.
|
||||
- The retained guard QEMU remained unchanged and reachable at PID `26318`,
|
||||
port `9222`, with process start ticks `1102996924`.
|
||||
- The base image remained mode `0444`, size `16515530752` bytes, and mtime
|
||||
`1786418212`. Its retained SHA-256 record is
|
||||
`67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef`;
|
||||
the final run intentionally did not repeat the expensive 16 GB hash.
|
||||
- At validation completion, `HEAD` and `xdm/main` both identified
|
||||
`a55e42a117e504f6ece49be3c2a2d81603031ea3`, and the worktree was clean.
|
||||
|
||||
This report is documentation-only and does not alter the validated DUT source
|
||||
tree `d63c45c7872dcf9dd84007c8883cf9fbe0f9467d`.
|
||||
|
||||
## Deferred feature work
|
||||
|
||||
The following issues remain unresolved and require dedicated behavior design,
|
||||
fixtures, or feature tests before any future implementation can be accepted:
|
||||
|
||||
- inode decode split or rewrite;
|
||||
- map request interface conversion;
|
||||
- directory/namei control flow, qstr, cookies, namecache, and lock behavior;
|
||||
- metadata reader consolidation;
|
||||
- rejection or handling of a non-directory root;
|
||||
- `run_len == 0` behavior;
|
||||
- header-only xattr behavior;
|
||||
- duplicate or missing `device.N` behavior;
|
||||
- `insmntque` race closure;
|
||||
- explicit extent and explicit mapped-extent fixtures;
|
||||
- `vnode_create_vobject` errno behavior.
|
||||
|
||||
No claim is made that these issues were fixed or covered by the ordinary
|
||||
smoke run. The final PASS is limited to the Pre12 static review, both KLD build
|
||||
configurations, KLD lifecycle, and the Plain/LZ4/LZMA smoke cases recorded in
|
||||
the accepted evidence directory.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Pre13 Baseline
|
||||
|
||||
- Source commit: `35eb53c65a4f75ba580f64af043779b930e3bb78`
|
||||
- `repo-pre-12` tree: `4ea4d7cfbf8b8a884b291f7433e19ce8e5af5a11`
|
||||
- `repo-pre-12/src` tree: `d63c45c7872dcf9dd84007c8883cf9fbe0f9467d`
|
||||
- `repo-pre-13/src` tree after copy: `d63c45c7872dcf9dd84007c8883cf9fbe0f9467d`
|
||||
- Copy verification: 327 files, 43 directories, and 0 symbolic links matched by relative path, mode, link target, and SHA-256 content manifest before this document was added.
|
||||
- Copy manifest SHA-256: `c6bdcee893a45a03308897715062aada41c591a82432f2c0008dbd316d10cf07`
|
||||
|
||||
Except for this baseline document, `repo-pre-13` is an exact copy of `repo-pre-12`.
|
||||
@@ -0,0 +1,90 @@
|
||||
# Pre13 Execution Status
|
||||
|
||||
## Final Status
|
||||
|
||||
Pre13 is **scoped PASS** for the planned and admitted Pre13 work at
|
||||
`b804d7b77d1c76b8e844dc4a758c6ab3381ca006`. This is not a full feature-suite
|
||||
PASS and does not claim V02 positive coverage.
|
||||
|
||||
At status backfill time, DUT `HEAD`, local `main`, fetched `xdm/main`, remote
|
||||
`refs/heads/main`, and the DUT worktree all resolve to
|
||||
`b804d7b77d1c76b8e844dc4a758c6ab3381ca006`; the DUT worktree is clean.
|
||||
|
||||
## Completed Source Work
|
||||
|
||||
- Low-risk alignment commits:
|
||||
- L-A1 helper/guard alignment:
|
||||
`2d0041ba3a195c184a52bdccae3bd00af520d4b7`
|
||||
- L-A2 helper ordering:
|
||||
`190a0b908d25e62b5c78ba82377f53d359fc5c4f`
|
||||
- L-B semantic type alignment:
|
||||
`f236836a55ad7ec7d536df483460ea394e38b6c3`
|
||||
- L-C1 on-disk endian field typing:
|
||||
`217b7a3032ec917c5ea63652b0f3cad734990d48`
|
||||
- L-C2 flexible on-disk arrays:
|
||||
`e72ecd7cc024047f0ce7c1855e6e44ae7f5350e1`
|
||||
- L-D LZ4 endian helper:
|
||||
`fe338f701059de8dfd6336dea7f9288bc0f12e9f`
|
||||
- L-E localized private constants:
|
||||
`9028b92343ec7f5bbc1b07477b8d4a669c436955`
|
||||
- Stage0 decisions:
|
||||
`8ed80c3ddbedc64b8b80daf1be16b28c4f24f10d`.
|
||||
- H04 root-type validation:
|
||||
`ee9dc4715436eeee21ae2d84eab2677b27d87ddd`.
|
||||
- H03 qstr lookup alignment:
|
||||
- H03a bounded qstr comparator:
|
||||
`f51b0fe1ceb27cac641667aa5688d371a60d2d99`
|
||||
- H03b lookup search propagation:
|
||||
`3313d305a2193ef6ffa26c6a189e47187b9c0d70`
|
||||
- H03c VOP adapter:
|
||||
`83a5bef73b329c967bd8390a0966d30005295758`
|
||||
- Build/test-input fixups:
|
||||
`dc47e8f99c947d2929d3528a6c139a85eb4251d5`,
|
||||
`b804d7b77d1c76b8e844dc4a758c6ab3381ca006`.
|
||||
|
||||
## Stage0 Decisions
|
||||
|
||||
- H04 ROOT-NONDIR: `READY`, then implemented and custom validated.
|
||||
- H07 ZERO-RUN: `STOP/no-op`; 1,360 legal states showed no reachable
|
||||
zero-progress path.
|
||||
- H01a/b/c map request work: `STOP`; the tuple oracle lacked chunk,
|
||||
multidevice, bounds, and overflow coverage.
|
||||
- H03 comparator: `READY`; Python 11,562 cases and C 1,048,576 cases passed.
|
||||
- Device-option probing: blocked/non-gating, no behavior claim.
|
||||
|
||||
## Validation Status
|
||||
|
||||
- Targeted build/layout/probe retry:
|
||||
`/work/tests-dev/temp/pre13-targeted-final-runnerfix-retry-20260814T0138Z`.
|
||||
`WITH_ZSTDIO=0` and `WITH_ZSTDIO=1` builds passed with module SHA256
|
||||
`0b1244cf9b7fe70649bdcc1c6ef12e6151c77b10c2755b366f960b101ccb7220`
|
||||
and `15db1fbf9450259d030e88602e1c5ba2e452a731c641b359bd5a2d7823da2735`.
|
||||
Layout probe and four userspace probe builds passed.
|
||||
- H04 custom fixture: PASS. Valid root mounted/remounted; non-directory root
|
||||
returned exact `EINTEGRITY` (`97`); failed mount left the provider
|
||||
detachable.
|
||||
- H03 targeted feature cases: PASS for TC042, TC043, TC044, TC045, TC053,
|
||||
TC054, TC123, TC141, and TC148. TC141's raw runner failure was an extra
|
||||
empty `umount ''` false negative after 25 real commands passed. TC148
|
||||
covered 320 files, 322 dirents, content, and empty suspect dmesg.
|
||||
- Final smoke:
|
||||
`/work/tests-dev/temp/pre13-missing-and-smoke-20260814T021330Z/final-summary.md`.
|
||||
Plain, LZ4, and LZMA passed; KLD load/stat/unload and cleanup passed.
|
||||
- V01 race:
|
||||
`/work/tests-dev/temp/pre13-v01-race-20260814T031032Z/retry-fresh-20260814T032500Z`.
|
||||
Raw runner FAIL was reclassified by the final offline analyzer at tests-dev
|
||||
`22c0bea73b9b81cc44385d1ba7103fa820c56070` as
|
||||
`DUT PASS / TEST false-negative-corrected`. The four offline analyzer unit
|
||||
tests passed. Dmesg total delta was 24 lines / 1,266 bytes with suspect
|
||||
bytes 0.
|
||||
|
||||
## Explicit Non-Claims
|
||||
|
||||
- No full feature suite was run.
|
||||
- No V02 positive explicit-extent fixture was produced; V02 remains PARTIAL.
|
||||
- TC004, TC011, TC143, TC144, TC145, TC150, and other unlisted feature cases
|
||||
are not claimed as passing.
|
||||
- H01, H07, H05, H06, H02, and H08 source changes were intentionally stopped,
|
||||
rejected, or no-op as recorded in the final report.
|
||||
|
||||
Detailed evidence and limits are recorded in `pre13-final-report.md`.
|
||||
@@ -0,0 +1,344 @@
|
||||
# Pre13 Final Report
|
||||
|
||||
## Conclusion
|
||||
|
||||
Pre13 is **scoped PASS** for the planned and admitted Pre13 work:
|
||||
|
||||
- DUT baseline snapshot: `a587d489b829ef8e7fac94c87130b61d47aa3e44`.
|
||||
- Final DUT commit: `b804d7b77d1c76b8e844dc4a758c6ab3381ca006`.
|
||||
- At final report time, `HEAD`, local `main`, fetched `xdm/main`, remote
|
||||
`refs/heads/main`, and the only DUT worktree all resolve to
|
||||
`b804d7b77d1c76b8e844dc4a758c6ab3381ca006`.
|
||||
- DUT working tree is clean.
|
||||
|
||||
This is **not** a full-filesystem certification. No full 161-case feature
|
||||
suite was run, no positive V02 explicit-extent fixture was produced, and Pre13
|
||||
does not claim that unrun cases such as TC004, TC011, TC143, TC144, TC145,
|
||||
TC150, or other non-targeted feature cases passed.
|
||||
|
||||
## Commit Inventory
|
||||
|
||||
The audited DUT range is
|
||||
`a587d489b829ef8e7fac94c87130b61d47aa3e44..b804d7b77d1c76b8e844dc4a758c6ab3381ca006`.
|
||||
|
||||
### Planning and Stage0
|
||||
|
||||
- `76a4c82`, `fd300cb`, `2f487f0`: Pre13 planning documents and low-risk batch
|
||||
accounting.
|
||||
- `8ed80c3ddbedc64b8b80daf1be16b28c4f24f10d`: recorded Stage0 gate decisions
|
||||
in `repo-pre-13/docs/pre13-stage0-decisions.md` and the initial execution
|
||||
status.
|
||||
|
||||
### Low-Risk Source Alignment
|
||||
|
||||
- `2d0041ba3a195c184a52bdccae3bd00af520d4b7`: L-A1 helper and guard alignment
|
||||
across `compress.h`, `data.c`, `erofs_fs.h`, and `inode.c`, with
|
||||
`pre13-low-a1.md`.
|
||||
- `190a0b908d25e62b5c78ba82377f53d359fc5c4f`: L-A2 local helper ordering in
|
||||
`decompressor.c` and `xattr.c`, with `pre13-low-a2.md`.
|
||||
- `f236836a55ad7ec7d536df483460ea394e38b6c3`: L-B semantic `erofs_nid_t` and
|
||||
`erofs_off_t` alignment across data, directory, inode, namei, super, xattr,
|
||||
zdata, and zmap paths, with `pre13-low-b.md`.
|
||||
- `217b7a3032ec917c5ea63652b0f3cad734990d48`: L-C1 on-disk `__leXX` field
|
||||
alignment in `erofs_fs.h` and initial `pre13_ondisk_layout_probe.c`, with
|
||||
`pre13-low-c1.md`.
|
||||
- `e72ecd7cc024047f0ce7c1855e6e44ae7f5350e1`: L-C2 flexible on-disk arrays
|
||||
and layout probe updates, with `pre13-low-c2.md`.
|
||||
- `fe338f701059de8dfd6336dea7f9288bc0f12e9f`: L-D LZ4 offset endian helper in
|
||||
`decompressor_lz4.c`, with `pre13-low-d.md`.
|
||||
- `9028b92343ec7f5bbc1b07477b8d4a669c436955`: L-E localized private
|
||||
constants, removed `erofs_defs.h`, and updated consumers/docs.
|
||||
|
||||
### Behavior Changes and Fixups
|
||||
|
||||
- `ee9dc4715436eeee21ae2d84eab2677b27d87ddd`: H04 rejects non-directory root
|
||||
inodes during mount, with `pre13-h04-root-validation.md`.
|
||||
- `f51b0fe1ceb27cac641667aa5688d371a60d2d99`: H03a introduced the bounded
|
||||
qstr comparator.
|
||||
- `3313d305a2193ef6ffa26c6a189e47187b9c0d70`: H03b passed qstr through block
|
||||
and dirent lookup search.
|
||||
- `83a5bef73b329c967bd8390a0966d30005295758`: H03c adapted VOP lookup to the
|
||||
bounded qstr path.
|
||||
- `dc47e8f99c947d2929d3528a6c139a85eb4251d5`: fixed const-correct build inputs
|
||||
and the userspace layout probe `bool` include issue.
|
||||
- `b804d7b77d1c76b8e844dc4a758c6ab3381ca006`: retired stale decompression test
|
||||
harnesses that no longer matched the current module surface; this did not hide
|
||||
a DUT test failure.
|
||||
|
||||
## Stage0 Gate Results
|
||||
|
||||
Stage0 was a mixed gate result, not an overall PASS:
|
||||
|
||||
- Gate A, ROOT-NONDIR: **READY**. The baseline accepted a non-directory root;
|
||||
Pre13 froze the rejection as `EINTEGRITY` and allowed H04.
|
||||
- Gate B, ZERO-RUN: **STOP/no-op**. The analysis covered 1,360 legal states and
|
||||
found no reachable zero-progress state for H07.
|
||||
- Gate C, map tuple oracle: **STOP**. The oracle covered only 26 plain,
|
||||
inline, and hole tuples; it did not cover chunk, multidevice, bounds, or
|
||||
overflow behavior, so H01a/H01b/H01c were not implemented.
|
||||
- Gate D, qstr comparator: **PASS/READY**. The Python comparator corpus passed
|
||||
11,562 cases and the independent C harness passed 1,048,576 cases.
|
||||
- Gate E, device option probe: **blocked/non-gating**. It produced no runtime
|
||||
behavior claim and did not block Pre13.
|
||||
|
||||
## Intentional Stops and Rejects
|
||||
|
||||
- H01 map objectization: **STOP** because the tuple oracle was incomplete for
|
||||
chunk, multidevice, bounds, and overflow coverage.
|
||||
- H07 zero-run: **STOP/no-op** because 1,360 legal states produced no reachable
|
||||
zero-progress path.
|
||||
- H05 header-only xattr: **rejected**; Linux treats the format as undefined and
|
||||
BSD already returns `EOPNOTSUPP`.
|
||||
- H06 duplicate `device.N`: **rejected/no-op** for source changes because
|
||||
`vfs_sanitizeopts()` makes the EROFS duplicate-option check unreachable; any
|
||||
probe is non-gating.
|
||||
- H02 inode split: **rejected** because it would diverge from Linux's single
|
||||
`erofs_read_inode()` switch and create low-value churn.
|
||||
- H08 pager errno propagation: **rejected** because the target
|
||||
`vnode_create_vobject()` path observably returns 0.
|
||||
- V02 explicit extent positive coverage: **PARTIAL**. No positive mapped
|
||||
fixture was available, and TC157 negative coverage is not a substitute.
|
||||
|
||||
## Build, Layout, and Probe Evidence
|
||||
|
||||
Primary evidence:
|
||||
`/work/tests-dev/temp/pre13-targeted-final-runnerfix-retry-20260814T0138Z`.
|
||||
|
||||
After `dc47e8f` and `b804d7b`, the targeted retry produced:
|
||||
|
||||
- `WITH_ZSTDIO=0` build: PASS, module SHA256
|
||||
`0b1244cf9b7fe70649bdcc1c6ef12e6151c77b10c2755b366f960b101ccb7220`.
|
||||
- `WITH_ZSTDIO=1` build: PASS, module SHA256
|
||||
`15db1fbf9450259d030e88602e1c5ba2e452a731c641b359bd5a2d7823da2735`.
|
||||
- Loaded module in that targeted run: SHA256
|
||||
`15db1fbf9450259d030e88602e1c5ba2e452a731c641b359bd5a2d7823da2735`.
|
||||
- Userspace layout probe: build and run return code 0.
|
||||
- Four userspace probe builds: `g3_vfs_probe`, `mount_errno_probe`,
|
||||
`nfs_fh_tool`, and `readdir_probe` all returned 0.
|
||||
|
||||
The first targeted runner attempt still ended host-side FAIL because TC141
|
||||
included an extra empty `umount ''` command. That was classified as a test
|
||||
runner false negative, not a DUT failure: the 25 real TC141 commands all had
|
||||
return code 0, and only the 26th synthetic empty unmount failed.
|
||||
|
||||
## H04 Root Validation
|
||||
|
||||
Evidence path:
|
||||
`/work/tests-dev/temp/pre13-targeted-final-runnerfix-retry-20260814T0138Z/guest-evidence/cases/H04`.
|
||||
|
||||
H04 custom fixture result: **PASS**.
|
||||
|
||||
- Valid root fixture SHA256:
|
||||
`d0baba501ae12fcdb8869a98908486473d2bcfb6b332a47cb6a6c1f856a3ab34`.
|
||||
- Non-directory root fixture SHA256:
|
||||
`60bf0d0d93baabdfa23b71f48283d317f6b7218852f3d19aee77575c41500db7`.
|
||||
- Root proof payload SHA256:
|
||||
`0ebc44a6c5a02ba458d1a115bc338fa4acb4d973a37804c9b926eafc0c53575f`.
|
||||
- Valid root mounted, root mode was `040755`, payload matched, and unmount plus
|
||||
`md` detach succeeded.
|
||||
- Non-directory root returned exact `mount_errno=97` (`EINTEGRITY`) with message
|
||||
`erofs: root inode nid=36 is not a directory`; the failed mount left the
|
||||
provider detachable.
|
||||
- The valid fixture remounted successfully after the non-directory failure.
|
||||
- Per-case dmesg delta and suspect logs were empty.
|
||||
|
||||
TC011 and TC150 were not run and are not claimed as passing. They are not
|
||||
Pre13 blockers because the dedicated H04 fixture directly exercised the actual
|
||||
root-type change, including the valid control, exact errno, detach, and remount
|
||||
properties.
|
||||
|
||||
## H03 Targeted Feature Evidence
|
||||
|
||||
H03 targeted cases exercised the qstr lookup changes and passed for:
|
||||
TC042, TC043, TC044, TC045, TC053, TC054, TC123, TC141, and TC148.
|
||||
|
||||
Evidence:
|
||||
|
||||
- TC042/043/044/045/053/054/123 and TC141 raw evidence:
|
||||
`/work/tests-dev/temp/pre13-targeted-final-runnerfix-retry-20260814T0138Z`.
|
||||
- TC148 valid copied evidence and final smoke summary:
|
||||
`/work/tests-dev/temp/pre13-missing-and-smoke-20260814T021330Z/final-summary.md`.
|
||||
|
||||
TC141 details:
|
||||
|
||||
- The runner logged 26 commands, but the last was the invalid empty
|
||||
`umount ''` cleanup bug.
|
||||
- The 25 real commands passed: valid-base and valid-padding cold lookup/read,
|
||||
repeated missing lookups returning `ENOENT`, `entries=322` wide-directory
|
||||
checks, and three corrupt lookup fixtures returning repeated
|
||||
`EINTEGRITY` (`errno=97`).
|
||||
- The only failure was the empty unmount runner command. Its stderr was
|
||||
`statfs: No such file or directory` / `unknown file system`, with no DUT
|
||||
dmesg delta.
|
||||
|
||||
TC148 details:
|
||||
|
||||
- Outcome: PASS.
|
||||
- Fixture SHA256:
|
||||
`9a94e9af2cab264b9c11975a20d78e615d6fe1e6f86267173cb5ac86aecb2b17`.
|
||||
- Mount command return code: 0.
|
||||
- Expected and actual regular-file count: 320.
|
||||
- Directory oracle: 322 entries, with two directories and 320 regular files.
|
||||
- `d_off` restart count and `seekdir` restart count: 322 each.
|
||||
- Target content matched.
|
||||
- Per-case dmesg delta and suspect log were empty.
|
||||
|
||||
## Final Smoke Evidence
|
||||
|
||||
Evidence path:
|
||||
`/work/tests-dev/temp/pre13-missing-and-smoke-20260814T021330Z/final-summary.md`.
|
||||
|
||||
Final smoke outcome: **PASS**.
|
||||
|
||||
- DUT archive SHA256:
|
||||
`d0c052bfef024d0acb40e107800cc8e8227fab6b691e8825af5cf01f19672fe4`.
|
||||
- Assets SHA256:
|
||||
`a9741ea468493bdc72d399615892d7f6269226467d09fa6613fa01352f011908`.
|
||||
- Probe bundle SHA256:
|
||||
`7b10d23c8a780fb35810fe85626305a8c49f196d270f98e5224045bd79f51066`.
|
||||
- Clean tests-dev worktree commit used for the smoke:
|
||||
`f86799654a37cdb81025b9e703635f7c7812fecb`.
|
||||
- `WITH_ZSTDIO=0` build: PASS, module SHA256
|
||||
`0b1244cf9b7fe70649bdcc1c6ef12e6151c77b10c2755b366f960b101ccb7220`.
|
||||
- `WITH_ZSTDIO=1` build: PASS, module SHA256
|
||||
`15db1fbf9450259d030e88602e1c5ba2e452a731c641b359bd5a2d7823da2735`.
|
||||
- Loaded module for final smoke: `WITH_ZSTDIO=0`, SHA256
|
||||
`0b1244cf9b7fe70649bdcc1c6ef12e6151c77b10c2755b366f960b101ccb7220`.
|
||||
- `kldload`, `kldstat -n erofs.ko`, `kldunload`, and final KLD cleanup: PASS.
|
||||
- Plain fixture SHA256:
|
||||
`3785ca07e7bd16f6c611191596ae0314253c0ae9b7217a4b22de25799b0f08ac`;
|
||||
payload SHA256 matched
|
||||
`056f8f7585667dc695e2edf936deaf84cfee0f88671ba6cd5be22ce890763433`.
|
||||
- LZ4 fixture SHA256:
|
||||
`967cc1b625546f9f9f881472e71cc3d849c65feb4e98e67fbfdc9b90a4be6dda`;
|
||||
payload SHA256 matched
|
||||
`3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880`.
|
||||
- LZMA fixture SHA256:
|
||||
`32107a084b27362a093768b88746c37c2e99a74b9f1301a9d4046988479defe9`;
|
||||
payload SHA256 matched
|
||||
`ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461`.
|
||||
- Every attach, mount, hash, unmount, and detach command returned 0.
|
||||
- Per-case and global dmesg suspect logs were empty.
|
||||
- Global mount, md, KLD, QEMU, ControlMaster, overlay, and ports
|
||||
`10056`, `10057`, `10058` cleanup passed.
|
||||
- Guard QEMU PID `26318` and port `9222` were unchanged and reachable.
|
||||
- The main tests-dev worktree was dirty before and after with unchanged diff
|
||||
SHA256 `92d3808ab33ff9b22fa2ee3f8a854c1fc36effecb4dd6c0917ae7e80c57fc23a`;
|
||||
the clean tests worktree, not the dirty main worktree, was used as evidence.
|
||||
|
||||
The final summary explicitly states that no other TC, full feature suite,
|
||||
TC004, TC143, TC144, or TC145 was run. Pre13 preserves that limitation.
|
||||
|
||||
## V01 Race Evidence
|
||||
|
||||
Raw evidence:
|
||||
`/work/tests-dev/temp/pre13-v01-race-20260814T031032Z/retry-fresh-20260814T032500Z`.
|
||||
|
||||
tests-dev evidence commits were verified on `xdm/main`:
|
||||
|
||||
- `2269908cc3f721d57ae8138faef664a6bc4c7cc9`: added the V01 concurrent unmount
|
||||
race runner.
|
||||
- `374c9d8473e6638fa0c8e865fcfcfee141b13f0d`: fixed runner SSH command
|
||||
execution.
|
||||
- `22c0bea73b9b81cc44385d1ba7103fa820c56070`: corrected forced-unmount deadfs
|
||||
errno classification and added the offline analyzer/unit tests. Fetched
|
||||
`xdm/main` and remote `refs/heads/main` both resolve to this commit.
|
||||
|
||||
Original raw run:
|
||||
|
||||
- Raw host/guest outcome: FAIL, `guest race failed rc=41`.
|
||||
- DUT commit: `b804d7b77d1c76b8e844dc4a758c6ab3381ca006`.
|
||||
- Module SHA256:
|
||||
`15db1fbf9450259d030e88602e1c5ba2e452a731c641b359bd5a2d7823da2735`.
|
||||
- Fixture root-valid SHA256:
|
||||
`d0baba501ae12fcdb8869a98908486473d2bcfb6b332a47cb6a6c1f856a3ab34`.
|
||||
|
||||
Normal group:
|
||||
|
||||
- Duration 90 seconds, 8 workers, 154 loops.
|
||||
- `umount` returned accepted `EBUSY` 154 times; no successful unmount/remount.
|
||||
- Worker read/stat/open/fstat success counts were each 79,164.
|
||||
- Worker content mismatch, short reads, rejected errors, and dmesg suspect bytes
|
||||
were all 0.
|
||||
|
||||
Forced group:
|
||||
|
||||
- Duration 90 seconds, 8 workers, 125 loops.
|
||||
- Successful forced unmount/remount cycles: 125/125.
|
||||
- `stat ENOENT`: 102,165; `open ENOENT`: 16.
|
||||
- Raw rejected errors: 1,772, consisting of 882 `fstat EBADF` and 890
|
||||
`read ENXIO`.
|
||||
- The final mounted SHA matched the expected payload SHA in both normal and
|
||||
forced groups.
|
||||
|
||||
Final analyzer result from
|
||||
`scripts/analyze-pre13-v01-race-evidence.py` at
|
||||
`22c0bea73b9b81cc44385d1ba7103fa820c56070`:
|
||||
|
||||
- `normal_verdict=PASS`.
|
||||
- `forced_verdict=PASS`.
|
||||
- `forced_expected_deadfs_errors=1772`.
|
||||
- `forced_expected_deadfs_fstat_ebadf=882`.
|
||||
- `forced_expected_deadfs_read_enxio=890`.
|
||||
- `dut_verdict=PASS`.
|
||||
- `test_verdict=false-negative-corrected`.
|
||||
- `overall_verdict=DUT PASS / TEST false-negative-corrected`.
|
||||
|
||||
The `EBADF` and `ENXIO` results occur only after successful forced unmounts,
|
||||
when existing descriptors are taken over by `deadfs`; that is standard FreeBSD
|
||||
semantics and not a DUT instability.
|
||||
|
||||
The analyzer's four offline unit tests all passed:
|
||||
|
||||
- forced deadfs errors are corrected;
|
||||
- normal deadfs errno is rejected;
|
||||
- forced unrelated errno is rejected;
|
||||
- count mismatch is rejected.
|
||||
|
||||
V01 cleanup and integrity:
|
||||
|
||||
- QEMU stopped, V01 port released, overlay removed.
|
||||
- Base image mode, size, and mtime remained `444`, `16515530752`, and
|
||||
`1786418212`.
|
||||
- Guard VM was unchanged and reachable.
|
||||
- Guest mount/md/KLD owned-resource cleanup passed.
|
||||
- Total dmesg delta was 24 lines / 1,266 bytes, all known non-suspect
|
||||
`mangled entry` lines; suspect bytes were 0. This is not a zero-total-delta
|
||||
run.
|
||||
- The dirty main tests-dev worktree was unchanged; the independent clean
|
||||
worktree was clean.
|
||||
|
||||
## Static Review and Evidence Boundaries
|
||||
|
||||
Final static review of the Pre13 source delta found no production-source
|
||||
blocker, test backdoor, out-of-bounds issue, ABI/layout issue,
|
||||
lock/lifecycle issue, or errno issue requiring another DUT fix. The one
|
||||
dynamic item that was pending at that review point was documentation/status
|
||||
backfill; that was a reporting-sequence issue, not an unperformed test gate.
|
||||
|
||||
The source/test diff boundary was also reviewed:
|
||||
|
||||
- Production changes are limited to the planned low-risk alignment work, H04,
|
||||
H03, and build-input fixups.
|
||||
- The only new tracked test asset in the DUT repo is the userspace layout probe.
|
||||
- The stale decompression harness removals in `b804d7b` were documented and do
|
||||
not hide a failing Pre13 DUT test.
|
||||
|
||||
## Unrun or Non-Claimed Coverage
|
||||
|
||||
Pre13 deliberately does **not** claim:
|
||||
|
||||
- full feature-suite PASS;
|
||||
- TC004 PASS;
|
||||
- TC011 or TC150 PASS;
|
||||
- TC143, TC144, or TC145 PASS;
|
||||
- TC146/V02 positive explicit-extent PASS;
|
||||
- H01 map objectization behavior;
|
||||
- H07 zero-progress behavior;
|
||||
- H05/H06/H02/H08 source behavior changes.
|
||||
|
||||
The custom H04 fixture directly covers the actual H04 source change, so the
|
||||
absence of TC011/TC150 is not a blocker for the scoped Pre13 result. Likewise,
|
||||
the final smoke covers Plain/LZ4/LZMA smoke only; Deflate, ZSTD, partial, and
|
||||
other codec feature cases remain outside the Pre13 claim unless specifically
|
||||
listed above.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Pre13 H03a: bounded qstr comparator carrier
|
||||
|
||||
## Scope
|
||||
|
||||
- Added a private `struct erofs_qstr` to `src/namei.c` with explicit `name`
|
||||
and `end` pointers.
|
||||
- Converted `erofs_dirnamecmp()` to consume bounded qstr objects.
|
||||
- Kept the existing search helpers on their original pointer/length interface
|
||||
through a temporary local adapter. Block search, VOP lookup, vnode locking,
|
||||
namecache timing, errno handling, readdir, and cookies are unchanged.
|
||||
|
||||
## Static equivalence
|
||||
|
||||
- Search and disk lengths are still derived from the same pointer ranges.
|
||||
- `matched` is clamped to both ranges before comparison.
|
||||
- Comparison remains unsigned byte ordering, supports non-NUL search keys and
|
||||
embedded NUL bytes, and never assumes a trailing NUL at the disk boundary.
|
||||
- The adapter performs no allocation, copying, normalization, or error mapping.
|
||||
|
||||
## Comparator gate
|
||||
|
||||
Tests baseline: `ce03c283e6e2cb8f1b69c8eff21f7d06098a4fbe`.
|
||||
|
||||
- Python deterministic corpus: PASS, 11,562 cases.
|
||||
- Independent C harness: PASS, 1,048,576 cases.
|
||||
|
||||
These host comparator results prove the old and new comparison contracts are
|
||||
equivalent for the generated corpus. They are not dynamic filesystem feature
|
||||
test results. H03 still requires TC042, TC043, TC044, TC045, TC053, TC054,
|
||||
TC123, TC141, and TC148, followed by the final smoke test.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Pre13 H03b: qstr block and dirent search
|
||||
|
||||
## Scope
|
||||
|
||||
- Converted `find_target_dirent()` and `erofs_find_target_block()` to accept a
|
||||
bounded `struct erofs_qstr` search key.
|
||||
- Constructed bounded on-disk qstr objects from the same validated dirent name
|
||||
offsets and block end pointers used before this change.
|
||||
- Constructed a temporary search qstr inside `erofs_namei()` while retaining
|
||||
its original pointer/length external interface for H03c.
|
||||
- Removed the H03a legacy comparator adapter.
|
||||
|
||||
No changes were made to `dir.c`, readdir, cookies, buffer ownership, directory
|
||||
validation, binary-search decisions, errno selection, cleanup, VOP lookup,
|
||||
vnode locking, or namecache operations.
|
||||
|
||||
## Static evidence
|
||||
|
||||
- `erofs_dirnamecmp()` has exactly two call sites: the block-level first-name
|
||||
comparison and the candidate block's dirent comparison.
|
||||
- Both on-disk qstr end pointers use the same next `nameoff` or validated block
|
||||
boundary as the previous pointer arguments.
|
||||
- `erofs_find_target_block()` retains every `erofs_brelse()` path, candidate
|
||||
replacement, `EINTEGRITY` assignment, and `ENOENT` distinction.
|
||||
- `erofs_namei()` still releases the selected block once and returns `ENOENT`
|
||||
only for a true miss.
|
||||
- The `erofs_lookup()` control flow and all `cache_enter()`, `vn_vget_ino()`,
|
||||
`erofs_vget()`, and `cn_lkflags` uses are outside this stage's diff.
|
||||
|
||||
## Comparator gate
|
||||
|
||||
Tests baseline: `ce03c283e6e2cb8f1b69c8eff21f7d06098a4fbe`.
|
||||
|
||||
- Python deterministic corpus: PASS, 11,562 cases.
|
||||
- Independent C harness: PASS, 1,048,576 cases.
|
||||
|
||||
The comparator gates are host static-equivalence evidence, not dynamic feature
|
||||
tests. H03 still requires TC042, TC043, TC044, TC045, TC053, TC054, TC123,
|
||||
TC141, and TC148, followed by the final smoke test.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Pre13 H03c: qstr VOP lookup adapter
|
||||
|
||||
## Scope
|
||||
|
||||
- Changed the private `erofs_namei()` interface to accept the bounded qstr
|
||||
carrier directly.
|
||||
- Moved search qstr construction to the `erofs_lookup()` FreeBSD VOP adapter,
|
||||
using exactly `cn_nameptr` and `cn_namelen` after the existing length checks.
|
||||
- Removed the temporary qstr construction from `erofs_namei()`.
|
||||
|
||||
No changes were made to `componentname` validation, mutation rejection, `.` or
|
||||
`..` handling, vnode lock mode, `vn_vget_ino()`, `erofs_vget()`, namecache
|
||||
timing, errno mapping, readdir, directory cookies, or directory UIO handling.
|
||||
|
||||
## Static evidence
|
||||
|
||||
- The qstr search range is `[cn_nameptr, cn_nameptr + cn_namelen)` and does not
|
||||
require or inspect a trailing NUL.
|
||||
- The only `erofs_namei()` caller remains `erofs_lookup()`.
|
||||
- A true `ENOENT` remains the only result eligible for negative `cache_enter()`;
|
||||
`EINTEGRITY` and all other errors still return directly.
|
||||
- `ISDOTDOT` still selects `vn_vget_ino()` with the original `cn_lkflags`;
|
||||
ordinary hits still select `erofs_vget()` with the same lock flags.
|
||||
- The H03c diff does not modify any `cache_enter()`, vnode lookup, lock, cookie,
|
||||
readdir, or UIO statement.
|
||||
|
||||
## Comparator gate
|
||||
|
||||
Tests baseline: `ce03c283e6e2cb8f1b69c8eff21f7d06098a4fbe`.
|
||||
|
||||
- Python deterministic corpus: PASS, 11,562 cases.
|
||||
- Independent C harness: PASS, 1,048,576 cases.
|
||||
|
||||
The comparator gates are host static-equivalence evidence, not dynamic feature
|
||||
tests. Dynamic H03 validation remains pending for TC042, TC043, TC044, TC045,
|
||||
TC053, TC054, TC123, TC141, and TC148, followed by the final smoke test.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Pre13 H04 Root Inode Validation
|
||||
|
||||
## Scope
|
||||
|
||||
H04 adds one mount-time format check in `src/super.c`: the decoded root inode
|
||||
must have FreeBSD vnode type `VDIR`.
|
||||
|
||||
The check runs after packed and metabox inode initialization and before xattr
|
||||
prefix initialization or publication of `mp->mnt_data`. No vnode is created and
|
||||
no permanent root inode reference is retained.
|
||||
|
||||
## Error Contract
|
||||
|
||||
A decodable non-directory root violates the EROFS filesystem structure. The
|
||||
mount therefore fails with positive FreeBSD errno `EINTEGRITY`.
|
||||
|
||||
This intentionally differs from Linux's negative `EINVAL` return while keeping
|
||||
the same format rejection. `EINTEGRITY` matches the existing FreeBSD EROFS
|
||||
contract for decodable on-disk metadata that violates filesystem invariants.
|
||||
|
||||
## Ownership Review
|
||||
|
||||
- The temporary `struct erofs_node` is stack-owned and has no independent
|
||||
allocations or vnode references.
|
||||
- Decode failures and the type rejection use the existing `fail` path.
|
||||
- `erofs_sb_free()` releases extent-cache state, internal inodes, external
|
||||
devices, and the primary GEOM device in the established reverse order.
|
||||
- The failure occurs before xattr prefixes, mount data, mount flags, or a root
|
||||
vnode are published.
|
||||
- The legal directory-root path is unchanged after the new check.
|
||||
|
||||
## Validation Gate
|
||||
|
||||
The required targeted QEMU validation is:
|
||||
|
||||
1. Build and load the current DUT module.
|
||||
2. Mount the valid paired fixture, verify mode `040755`, read its proof file,
|
||||
and unmount it.
|
||||
3. Mount the non-directory-root fixture and require exact errno `EINTEGRITY`.
|
||||
4. Verify mount, md, KLD, and GEOM resources return to zero, then remount the
|
||||
valid fixture.
|
||||
5. Verify the kernel log has no panic, trap, or lock warning.
|
||||
|
||||
No full feature suite is part of H04.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Pre13 L-A1
|
||||
|
||||
This batch aligns the remaining low-risk helper vocabulary with Linux:
|
||||
|
||||
- `compress.h` now uses the Linux include guard name.
|
||||
- `erofs_inode_is_data_compressed()` replaces four equivalent FULL/COMPACT
|
||||
tests that do not need to distinguish the two layouts.
|
||||
- `erofs_addrmask()` directly uses the existing 48-bit feature helper.
|
||||
|
||||
Static proof:
|
||||
|
||||
- For every value from zero through `EROFS_INODE_DATALAYOUT_MAX`, the new
|
||||
compressed-layout helper equals the replaced boolean expression.
|
||||
- The helper was not substituted in `zmap.c`, where FULL and COMPACT remain
|
||||
distinct cases.
|
||||
- `erofs_is_48bit()` and `erofs_sb_has_48bit()` tested the same incompat bit;
|
||||
address-mask values and control flow are unchanged.
|
||||
- The old include guard and duplicate 48-bit helper have no remaining source
|
||||
consumers.
|
||||
|
||||
No build, QEMU, smoke, or feature test was run for this batch.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Pre13 L-A2
|
||||
|
||||
This batch mechanically aligns two local declaration groups with Linux:
|
||||
|
||||
- The xattr prefix cleanup/init functions follow the public get/list entry
|
||||
points and precede the ACL entry point.
|
||||
- The shifted/interlaced decompressor descriptors precede the LZ4 descriptor.
|
||||
|
||||
Only complete blocks moved. No prototype, function body, callback, conditional
|
||||
compilation, or indexed descriptor slot changed. Pre-move and post-move hashes
|
||||
of both xattr functions and all three descriptor definitions are identical;
|
||||
the indexed descriptor table is byte-identical.
|
||||
|
||||
No build, QEMU, smoke, or feature test was run for this batch.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Pre13 L-B
|
||||
|
||||
This batch completes the planned semantic aliases for internal EROFS NIDs and
|
||||
byte offsets. Each changed object was selected from the Pre13 variable-level
|
||||
whitelist.
|
||||
|
||||
The aliases remain unsigned 64-bit types. No expression, cast, format string,
|
||||
error path, field order, or control flow changed. File sizes, lengths, chunk
|
||||
and extent indexes/counts, directory cookies, media sizes, timestamps, disk
|
||||
fields, and overflow-only temporaries retain their previous types.
|
||||
|
||||
Declarations and definitions were updated together. The resulting source diff
|
||||
contains only type tokens, line wrapping required by those tokens, and this
|
||||
record.
|
||||
|
||||
No build, QEMU, smoke, or feature test was run for this batch.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Pre13 L-C1
|
||||
|
||||
This batch aligns the endian type vocabulary of named multi-byte on-disk
|
||||
fields with the corresponding Linux EROFS declarations.
|
||||
|
||||
Only fields for which the same Linux structure and field use `__le16`,
|
||||
`__le32`, or `__le64` were changed. Byte fields, arrays, field order, unions,
|
||||
packing, macros, and all read/conversion sites remain unchanged. The direct
|
||||
disk-type parameter of `erofs_xattr_ibody_size()` was synchronized.
|
||||
|
||||
The FreeBSD compatibility aliases map each `__leXX` type to the exact previous
|
||||
unsigned integer type. A host-side probe compared 119 structure/union
|
||||
size/alignment and named-field offset entries before and after the batch; all
|
||||
values were identical. `tests/pre13_ondisk_layout_probe.c` retains legacy
|
||||
definitions and exhaustive assertions for every modified structure so the
|
||||
same proof can be compiled with the final FreeBSD guest toolchain. Existing
|
||||
kernel `_Static_assert` checks remain unchanged.
|
||||
|
||||
No KLD build, QEMU, smoke, or feature test was run for this batch.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Pre13 L-C2
|
||||
|
||||
The two planned zero-length on-disk tail arrays now use standard flexible array
|
||||
declarators:
|
||||
|
||||
- `erofs_xattr_ibody_header::h_shared_xattrs`
|
||||
- `erofs_xattr_long_prefix::infix`
|
||||
|
||||
The layout probe retains the previous `[0]` declarations and asserts equal
|
||||
structure size/alignment and member offsets. Host Clang accepts both old and
|
||||
new declarations with the same warning/error result and identical layouts.
|
||||
The probe is also retained for the final FreeBSD guest compiler gate.
|
||||
|
||||
No KLD build, QEMU, smoke, or feature test was run for this batch.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Pre13 L-D
|
||||
|
||||
The LZ4 two-byte little-endian offset now uses FreeBSD's unaligned-safe
|
||||
`le16dec()` helper. Boundary checks, input advancement, zero/back-reference
|
||||
validation, partial decoding, padding validation, and error returns are
|
||||
unchanged.
|
||||
|
||||
An exhaustive 65,536-value comparison proved `ip[0] | (ip[1] << 8)` and
|
||||
`le16dec(ip)` equivalent for every possible encoded offset. The final FreeBSD
|
||||
KLD and LZ4 smoke gates remain required later; this phase does not run them.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Pre13 L-E
|
||||
|
||||
The BSD-only miscellaneous `erofs_defs.h` has been removed. Its three owners
|
||||
now keep their constants in the files responsible for those values:
|
||||
|
||||
- `super.c` owns the named private CRC32C seed.
|
||||
- `dir.c` uses `sizeof(struct erofs_dirent)` directly.
|
||||
- `decompressor_lz4.c` owns its private LZ4 format constants.
|
||||
|
||||
The former header had exactly these three production source consumers. All
|
||||
constant values and use-site expressions remain equivalent. Two already
|
||||
retired userspace decompression test files still referenced the removed header;
|
||||
they were deleted because they also depended on obsolete userspace ABIs and did
|
||||
not compile independently. No current source or test entry retains the old
|
||||
include. The LZ4 macro names remain private to `decompressor_lz4.c`; the former
|
||||
shared CRC and dirent macro names have no current consumers. The current
|
||||
architecture file was updated; historical reports were not changed.
|
||||
|
||||
No KLD build, QEMU, smoke, or feature test was run for this batch.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Pre13 Stage0 Gate Decisions
|
||||
|
||||
## Scope and Baseline
|
||||
|
||||
- DUT repository baseline: `9028b92343ec7f5bbc1b07477b8d4a669c436955`.
|
||||
- Clean tests-dev baseline: `ce03c283e6e2cb8f1b69c8eff21f7d06098a4fbe`.
|
||||
- Stage0 was a planning gate. Infrastructure fixes made in tests-dev are not DUT changes.
|
||||
- The complete Stage0 runner result is `FAIL`, not `PASS`, because the H01 DTrace probe failed.
|
||||
|
||||
## Gate A: ROOT-NONDIR
|
||||
|
||||
Status: `READY`.
|
||||
|
||||
The baseline incorrectly mounts an image whose root NID points to a regular file. Pre13 freezes the expected rejection errno as `EINTEGRITY`. H04 may proceed with the dedicated fixture and its required targeted validation.
|
||||
|
||||
## Gate B: ZERO-RUN
|
||||
|
||||
Status: `BLOCKED/STOP`.
|
||||
|
||||
The analysis covered 1,360 legal states and found no zero-progress state. H07 must be recorded as a no-op and must not be implemented in Pre13.
|
||||
|
||||
## Gate C: Map Tuple Oracle
|
||||
|
||||
Status: `BLOCKED/STOP`.
|
||||
|
||||
The oracle reliably covers only 26 plain, inline, and hole tuples. It does not cover chunk, multidevice, bounds, or overflow behavior. H01a, H01b, and H01c must not be implemented in Pre13.
|
||||
|
||||
## Gate D: Comparator
|
||||
|
||||
Status: `READY`.
|
||||
|
||||
The Python comparator corpus passed all 11,562 cases. The independent C harness passed all 1,048,576 cases. H03 may proceed within the planned boundaries and with its targeted validation.
|
||||
|
||||
## Gate E: Device Options
|
||||
|
||||
Status: incomplete and non-gating.
|
||||
|
||||
The `device.N` runtime probe was not completed. Pre13 makes no runtime behavior claim from this gate.
|
||||
|
||||
## Integrity and Cleanup
|
||||
|
||||
- Stage0 must not be described as an overall pass.
|
||||
- Stage0-owned QEMU, SSH, ports, overlays, and temporary runtime resources were cleaned up.
|
||||
- The guard VM and read-only base image were not modified.
|
||||
- The pre-existing dirty tests-dev working tree was unchanged.
|
||||
- Tests-dev runner and infrastructure repairs are evidence support only; they are not EROFS DUT fixes.
|
||||
@@ -0,0 +1,40 @@
|
||||
# P15-005 Stage0 Decision
|
||||
|
||||
Status: `GO` for B06.
|
||||
|
||||
The authoritative baseline replay used commit
|
||||
`edf098905a34de764185e72fc7e92d7b8f4e7285`. The gate extracts and compiles
|
||||
the current FreeBSD `data.c` and `zmap.c` producer bodies instead of replaying
|
||||
an arithmetic model. Fourteen frozen cases cover plain, inline, hole, chunk,
|
||||
48-bit multidevice, compressed explicit extents, fragment, partial-reference,
|
||||
post-EOF, bounds, overflow, short-read, and post-acquire error behavior. Every
|
||||
field in `(m_la,m_pa,m_llen,m_plen,m_deviceid,m_flags,errno,acquire_count,
|
||||
release_count)` matched the independently frozen record oracle.
|
||||
|
||||
The ownership oracle freezes 27 audited function bodies and 22 success,
|
||||
validation-error, provider-error/short-read, transfer, and release paths across
|
||||
plain data, compressed data/config, xattr, inode, superblock, and map consumers.
|
||||
It also pins the corresponding Linux source hashes and `erofs_buf` acquire/put
|
||||
semantic anchors. Candidate replay must satisfy the predeclared per-function
|
||||
object/put/raw-buffer contract and execute the actual FreeBSD helper through
|
||||
primary-image, metabox, error, overflow, idempotent-put, and null-callback paths.
|
||||
|
||||
The supplied prep remains correctly classified `BLOCKED`: its static scan uses
|
||||
obsolete `erofs_mount`/`erofs_node` text anchors and its Python map model does
|
||||
not execute DUT code. `P15-005.sh` and `P15-005-input.json` close those gaps on
|
||||
the current BASE. Evidence is in
|
||||
`planning/pre15/evidence/20260814T145546Z-G02-P15-005/`.
|
||||
|
||||
QEMU and the full feature suite were not run. G02 for P15-005 is a host/source
|
||||
gate, and its candidate contract does not require either. This GO authorizes
|
||||
B06 only; it does not authorize P15-006 or any B07 map-object change.
|
||||
|
||||
## B06 completion
|
||||
|
||||
B06 commit `1b1f904a674c21eed3ee29ca7df93c44429ac8d5` replayed the same
|
||||
corpus and oracle with `object_mode=true`, `oracle_equal=true`, 14/14 tuples,
|
||||
22/22 ownership paths, and five actual helper lifecycle paths. D, the B06 host
|
||||
case, and both FreeBSD KLD configurations pass. Seven frozen FreeBSD raw I/O
|
||||
and GEOM lifecycle functions are unchanged, and the pre-B07 map object hash is
|
||||
unchanged. This completes the B06 dependency and unlocks B07a for its own
|
||||
separate gated batch; it does not pre-approve a B07 implementation.
|
||||
@@ -0,0 +1,60 @@
|
||||
# P15-006 Stage0 Decision
|
||||
|
||||
Status: `GO`; B07a is complete.
|
||||
|
||||
The authoritative baseline replay used commit
|
||||
`6673f51152a5195a8a8903aa801f820abce7936e`. This decision is independent of
|
||||
the earlier P15-005 GO: P15-006 has its own corpus, model digest, source
|
||||
extractors, byte encoding, and decision record.
|
||||
|
||||
The frozen corpus contains 80 map tuples and 13 device-resolution cases. The
|
||||
map tuples comprise 50 plain/inline/chunk producer cases and 30 compressed
|
||||
explicit-extent cases. They cover plain and inline boundaries, holes, raw
|
||||
32-bit chunks, indexed 32-bit chunks, indexed 48-bit chunks, masked and
|
||||
nonzero device IDs, all four explicit extent record sizes, fragments, partial
|
||||
references, exact and post EOF, provider/metabox bounds, checked arithmetic
|
||||
overflow, invalid formats and algorithms, and errors both before and after
|
||||
metadata acquisition. The device cases separately exercise primary,
|
||||
multidevice, flat-device, unified-address, missing-provider, range, and
|
||||
overflow behavior without changing GEOM ownership.
|
||||
|
||||
Expected records are produced by an independent arithmetic and on-disk record
|
||||
decoder whose frozen SHA256 is
|
||||
`effcf0b6cc6a6e916eae89a14ad52d7b96273a453556647b6eabf2926fcb4abb`.
|
||||
The gate separately extracts the real `data.c` and `zmap.c` producer bodies
|
||||
from the frozen BASE, compiles them with `-Werror`, and compares every
|
||||
`m_la`, `m_pa`, `m_llen`, `m_plen`, `m_deviceid`, `m_flags`,
|
||||
`m_algorithmformat`, positive errno, acquire count, and release count. It
|
||||
also packs those fields with fixed layout `<QQQQH2xIiiII`; the baseline tuple
|
||||
bytes have SHA256
|
||||
`8d3fec7ccbdfb7f7c851a494b6ecad02b8a019247bd9486188f8d37c169faedd`.
|
||||
Two complete baseline replays produced byte-identical tuple, device, and
|
||||
result files.
|
||||
|
||||
Protected hashes freeze the existing plain/chunk and compressed producers,
|
||||
metadata acquire/put paths, physical I/O path, and device/GEOM mapping bodies.
|
||||
The candidate replay additionally requires FULL and COMPACT dispatch to pass
|
||||
all five map flag bits and all tuple fields through the new adapter. Every
|
||||
observed acquisition is balanced: the baseline contains 41 paths at 0:0, 30
|
||||
at 1:1, seven at 2:2, and two at 3:3. All successful non-EOF mappings have a
|
||||
positive `m_llen`; Pre13 H07 remains closed.
|
||||
|
||||
This closes the specific Pre13 H01 oracle gaps for chunk, multidevice, bounds,
|
||||
and overflow rather than reusing the old 26 plain/inline/hole tuples. The
|
||||
supplied G02 prep remains a non-authoritative prototype and was not used as
|
||||
the tuple source.
|
||||
|
||||
The B07a implementation is commit
|
||||
`141b11f0d847a63a47b6c6143e4c2913a1147a0f`. Its authoritative host run
|
||||
replayed all 80 tuples and 13 device cases against the frozen oracle. The
|
||||
4,480-byte tuple streams are byte-identical with SHA256
|
||||
`8d3fec7ccbdfb7f7c851a494b6ecad02b8a019247bd9486188f8d37c169faedd`;
|
||||
FULL and COMPACT dispatch preserve every tuple field and all five map flag
|
||||
bits. D and both K2 configurations pass, with no global or undefined symbol
|
||||
delta from B06.
|
||||
|
||||
QEMU and the full feature suite were not run. The final plan requires host
|
||||
tuple replay, D, and K2 for B07a; it does not require a B07a QEMU fixture.
|
||||
B07b is now dependency-unblocked for a separate batch. B07c remains blocked
|
||||
on B07b, and B08 remains blocked on B07c. This decision neither implements
|
||||
nor pre-accepts any of those later batches.
|
||||
@@ -0,0 +1,102 @@
|
||||
# P15-019 Stage0 Decision
|
||||
|
||||
Status: `GO`. G03 authorizes B16 for P15-019 only. P15-046 remains the B01
|
||||
test-only legacy xattr prefix fallback contract; it neither changes this
|
||||
decision nor authorizes any exact-header or xattr behavior change.
|
||||
|
||||
The decision is bound to DUT BASE
|
||||
`d645feb720c7022d2138d2a62eb72c022eb75351`, FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils source HEAD
|
||||
`7db78788b000999e2de88decd2ba90654f26171c`, and
|
||||
`mkfs.erofs (erofs-utils) 1.8.6`.
|
||||
|
||||
## Authoritative Run
|
||||
|
||||
The gate ran from `/work/erofs-freebsd-pre/repo-pre-15` as:
|
||||
|
||||
```sh
|
||||
umask 077
|
||||
timeout -k 10 240 tests/pre15/gates/P15-019.sh \
|
||||
--base d645feb720c7022d2138d2a62eb72c022eb75351 \
|
||||
--output /work/erofs-freebsd-pre-evidence/pre15/\
|
||||
20260815T093800Z-G03-P15-019-umask-fix/gate-output
|
||||
```
|
||||
|
||||
It returned zero with `GO`. The authoritative hashes are:
|
||||
|
||||
- gate script: `afa20cbd28ca9dfc8064596a312248756ed7cde54398efb5ef713818cc04ea54`
|
||||
- gate input: `291bf12838981ef650e16bbf7381eaa9b2921de957e97dec46e6a573750a19b8`
|
||||
- result: `bb52e1a88cb09554a51432ec545ed98d5509a529832141ed0ce83b0c336be5bb`
|
||||
- cases: `0c12cdce8b3ed37e85f349af0715a728d4acabbb758451fb65546dd9836066b5`
|
||||
- fixture manifest/set: `5e99e5ad9112508991e78ae6e65928973d6b0da78285a059894bed06010cf373`
|
||||
- semantics: `090e6b0cd5eaa197f17da12daf29f30bd8f337d3d4ae2f0f4f5819ad41e906f9`
|
||||
- cleanup: `8e3b52610ee1492262494d00c48bf66ea04d313ab9ac1ef27565fa0e607b9a97`
|
||||
|
||||
An additional independent replay from `umask 077` produced the same result,
|
||||
cases, fixture manifest, semantics, and cleanup hashes byte for byte. The gate
|
||||
sets `umask 022` internally because erofs-utils records the packed fragment
|
||||
inode's source mode; this makes the fixture set independent of its caller.
|
||||
|
||||
## Real EROFS Fixture Oracle
|
||||
|
||||
The gate creates 35 deterministic EROFS images and seven external chunk blobs
|
||||
in owned output. Nothing is committed as an image, blob, binary, or KLD. Each
|
||||
of the five required storage paths has these seven cases:
|
||||
|
||||
- normal short target;
|
||||
- normal 1,024-byte `MAXPATHLEN` target;
|
||||
- zero-byte target;
|
||||
- embedded NUL at the first, middle, and last byte;
|
||||
- 1,025-byte over-limit target.
|
||||
|
||||
Inline positives are native mkfs symlinks. Plain, chunk, compact compressed
|
||||
ztailpacking, and whole-file fragment cases start as real mkfs regular-file
|
||||
carriers because the host cannot create a symlink containing NUL and mkfs does
|
||||
not select those layouts for symlinks. The transform changes only inode mode,
|
||||
the root dirent type, and, for empty cases, inode size, then recomputes the real
|
||||
EROFS checksum. Chunk data remains on a real `--blobdev`; fragment data remains
|
||||
in the real packed inode. Changed-byte offsets are recorded for every case.
|
||||
|
||||
The independent Python parser reads the superblock, checksum span, inode,
|
||||
dirent, layout, and target bytes directly. It resolves chunk indexes and the
|
||||
external blob, decodes compact inline-pcluster raw LZ4 without a DUT helper,
|
||||
and resolves the whole-fragment offset through the packed inode. It does not
|
||||
compile, call, or inject values into any DUT internal function. `dump.erofs`
|
||||
is only a layout/type cross-check. All legal targets also pass
|
||||
`fsck.erofs --extract` and reproduce the exact source bytes.
|
||||
|
||||
The independent decision model returns positive FreeBSD `EINTEGRITY` (97) for
|
||||
empty or embedded-NUL targets, positive `ENAMETOOLONG` (63) before target I/O
|
||||
for size greater than `MAXPATHLEN`, and success for exact non-NUL bytes. No
|
||||
trailing NUL is required. All 35 expected results match, so every layout has a
|
||||
bounded positive and negative oracle as required by G03.
|
||||
|
||||
## Linux and FreeBSD Semantics
|
||||
|
||||
Linux `erofs_fill_symlink()` validates only flat-inline fast symlinks while
|
||||
building `i_link`; it uses `kmemdup_nul()`/`strlen()` and returns negative
|
||||
`-EFSCORRUPTED`. Non-inline Linux symlinks use `page_get_link`. That page/cache
|
||||
shape is not a FreeBSD implementation contract.
|
||||
|
||||
FreeBSD enters through `VOP_READLINK` on a vnode and currently streams through
|
||||
`erofs_readlink_target`, the common map/read path, GEOM or the compressed
|
||||
backing path, and `uiomove`. It has no Linux `i_link` or page-get-link path and
|
||||
uses positive errno. B16 must therefore validate the complete immutable target
|
||||
before any `uiomove`, use the existing layout-specific map/read machinery, and
|
||||
keep the scan bounded by `MAXPATHLEN=1024`.
|
||||
|
||||
The 1,024-byte case is a successful `readlink(2)` byte target. Pathname follow
|
||||
may still return `ENAMETOOLONG` when that target plus the remaining pathname
|
||||
exceeds FreeBSD's namei buffer; that VFS result is distinct from the on-disk
|
||||
target validator. The 1,025-byte inode is rejected by B16 before target I/O.
|
||||
|
||||
## Scope and Cleanup
|
||||
|
||||
The gate did not modify `src/**`, build a KLD, start QEMU, or run a feature
|
||||
suite. It observed but did not signal or otherwise alter protected PID 26318,
|
||||
port 9222, or `/work/debug-qemu/local/vm-freebsd-build.qcow2.bp`; their recorded
|
||||
identity was unchanged before and after the run. Owned temporary source and
|
||||
extract directories were removed, with zero leftovers.
|
||||
|
||||
B16 may now modify only its planned source/test write set and must pass the
|
||||
specified host TC166, D, zstdio0 build, and targeted TC166 QEMU acceptance.
|
||||
@@ -0,0 +1,93 @@
|
||||
# P15-021 Stage0 Decision
|
||||
|
||||
Status: `GO`. B19b source is authorized; B19a remains `STOP-NO-SOURCE`.
|
||||
|
||||
P15-021 is the xattr Bloom fast-negative candidate. The gate uses a real,
|
||||
byte-reproducible EROFS image generated by `mkfs.erofs` 1.8.6, an independent
|
||||
on-disk parser, a temporary file-local `erofs_xxh32` prototype, frozen Linux
|
||||
format/use-site anchors, and five cold provider-metadata-read samples. It does
|
||||
not link a prototype into the DUT KLD and does not modify `src/**`.
|
||||
|
||||
The required matrix is hit, proven miss, collision false positive, unknown
|
||||
filter format, feature off, malformed shared-count metadata, malformed shared
|
||||
ID metadata, positive FreeBSD errno, 64-worker replay, one million generated
|
||||
names without a false negative, and owned cleanup. Unknown formats and feature
|
||||
off must scan. A collision must scan. Structural corruption reached before or
|
||||
during the scan must remain `EINTEGRITY` rather than becoming `ENOATTR`.
|
||||
|
||||
The gate command is:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 tests/pre15/gates/P15-021.sh \
|
||||
--base 666e52f710363df07f7c93919eb835d41092d011 \
|
||||
--output OUTPUT
|
||||
```
|
||||
|
||||
## Frozen Identity
|
||||
|
||||
The gate BASE is `666e52f710363df07f7c93919eb835d41092d011`.
|
||||
`P15-021-input.json` freezes the three DUT source files, Linux `erofs_fs.h` and
|
||||
`xattr.c`, FreeBSD 15 source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils HEAD
|
||||
`7db78788b000999e2de88decd2ba90654f26171c`, host tools, format constants,
|
||||
thresholds, seven endian/seed vectors, one million generated names, 64 workers,
|
||||
and the exact gate/source write sets. FreeBSD has no public xxh32 API; its only
|
||||
copies are private Zstd/OpenZFS sources, so the authorized implementation is
|
||||
file-local and namespaced as `erofs_xxh32`.
|
||||
|
||||
The generated prototype source SHA256 is
|
||||
`3fe1a7a64ce4386d74f5f49455fe8bef2a2ee55a03eb72593a89d4dec70c1b4b`.
|
||||
Its temporary host binary SHA256 is
|
||||
`9910baed4d018a0257f38377bb48857a3205ee42d9f0ff279db71e63e5ba695b`;
|
||||
the binary is evidence only, is not committed, and is never linked into the DUT
|
||||
KLD.
|
||||
|
||||
## Fixture And Oracle
|
||||
|
||||
`mkfs.erofs` 1.8.6 generated the filter-bearing image twice from 64 peers and
|
||||
one target with eight shared user xattrs. The two images were byte-identical;
|
||||
the valid fixture SHA256 is
|
||||
`b06b7c4c30adb3684d11505edf815dc0a395c03f6a95120b3150361008a182cb`.
|
||||
The independent parser handles multi-block directories and separately decodes
|
||||
inode xattr headers, inline entries, shared IDs, and shared entries. Legal
|
||||
valid, unknown-reserved, and feature-off images pass `fsck.erofs`.
|
||||
|
||||
The seven-case matrix passes: present hit, proven miss, collision false
|
||||
positive, unknown filter, feature off, malformed shared count, and out-of-range
|
||||
shared ID. Miss alone takes the fast-negative. Hit and collision perform the
|
||||
complete scan; unknown format and feature off perform the unchanged complete
|
||||
scan. Corrupt header/shared metadata returns positive FreeBSD `EINTEGRITY=97`,
|
||||
while valid absence returns positive `ENOATTR=87`.
|
||||
|
||||
The candidate implementation, independent Python xxh32, system libxxhash, and
|
||||
the frozen Linux seed/endianness vectors agree. One million deterministic random
|
||||
names across EROFS indexes 1/2/3/4/6 produce no candidate/oracle difference and
|
||||
no false negative in 1,024 constructed valid filters. Sixty-four workers
|
||||
complete 1,280 mixed lookups with identical bytes/errno.
|
||||
|
||||
## Benefit And Decision
|
||||
|
||||
Five cold samples of 200 real-fixture misses each are stable. Baseline metadata
|
||||
read calls are `3400,3400,3400,3400,3400`; candidate calls are
|
||||
`400,400,400,400,400`, an 88.235 percent reduction. Baseline cold unique
|
||||
provider blocks are `400,400,400,400,400`; candidate blocks are
|
||||
`200,200,200,200,200`, a 50 percent reduction. Both exceed the mandatory 25
|
||||
percent threshold. The model counts the extra header/shared-ID reads on
|
||||
positive and collision paths and therefore does not hide their overhead.
|
||||
|
||||
G03 is `GO` for P15-021. Only a proven negative may bypass the full scan; all
|
||||
other outcomes retain the current FreeBSD extattr namespace, VOP transfer,
|
||||
positive errno, metadata buffer ownership, and lock-free immutable lookup
|
||||
behavior. Linux supplies the format/hash comparison, not FreeBSD vnode/cache or
|
||||
locking semantics.
|
||||
|
||||
Attempt 1 stopped at the fixed-vector check because five hexadecimal hashes
|
||||
were transcribed to incorrect decimal JSON values. Python and libxxhash agreed
|
||||
on the hexadecimal values and bits; the input-only correction was replayed
|
||||
under a new output directory. Attempts 2 and 3 then produced identical semantic
|
||||
results and fixture hashes. Attempt 3 evidence is retained at
|
||||
`/work/pre15-evidence/20260815T-P15-021-G03-attempt-3`; its `SHA256SUMS` digest
|
||||
is `b81fe1b94048dbc3d17c62c95aba6a5de9e068e2a15639ca55ea60fe5a251e07`.
|
||||
No QEMU or full feature suite was run for the Stage0 decision. Source remained
|
||||
unchanged, owned temporary files/processes are zero, and protected PID 26318,
|
||||
port 9222, and the base bp were untouched.
|
||||
@@ -0,0 +1,87 @@
|
||||
# P15-022 Stage0 Decision
|
||||
|
||||
Status: `GO`. B19a source is authorized.
|
||||
|
||||
P15-022 is the G03/G05 xattr-cache candidate. The old decision was not treated
|
||||
as terminal because its multi-block path parser stopped before producing a
|
||||
P15-022 result and G05 had zero samples. The repaired gate completed both
|
||||
mandatory branches before source implementation.
|
||||
|
||||
## Frozen Identity
|
||||
|
||||
The replay base is `50a4e84d0da33592a81361e0294b7feb5bbd3ffa`.
|
||||
`P15-022-input.json` freezes the current DUT/Linux source, exact-ABI FreeBSD
|
||||
source `/work/dev-freebsd-releng` at
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, host tools, B17 assets, B19a
|
||||
generator/oracle/model assets, a 1 MiB mount budget, a 64 KiB per-vnode body
|
||||
limit, 64 workers, five samples per variant, and the unchanged 25 percent
|
||||
provider-metadata-read threshold.
|
||||
|
||||
## Oracle Repair And G03
|
||||
|
||||
The B19a oracle now reads every logical directory block, including a short
|
||||
final block, and validates name offsets, embedded NUL rules, strict in-block
|
||||
ordering, strict adjacent-block ordering, stable entry order, duplicate
|
||||
resolution, and missing-path classification. Its self-controls cover target
|
||||
lookup after a block boundary, duplicate within/across blocks, duplicate
|
||||
resolution, missing target, backwards boundary, and an invalid name range.
|
||||
|
||||
The real fixture retains 64 long-named peers and one target. It has 2 root
|
||||
directory blocks, 68 entries, and resolves `target.bin` in block 1 after the
|
||||
`peer-047`/`peer-048` boundary. The target contains both one inline xattr and
|
||||
one shared xattr. Valid, corrupt shared-count, corrupt shared-ID, and corrupt
|
||||
inline-name fixtures are independently checked with positive FreeBSD errno.
|
||||
|
||||
G03 completed twice on byte-reproducible images. The existing B17 oracle also
|
||||
replayed twice with all 10 legal and 15 damaged images passing and frozen
|
||||
fixture-set SHA256
|
||||
`d821aeb36de37ae40b817b91f8169e585721c33a3a9e59098cdfbcbfff74e364`.
|
||||
|
||||
## G05 Result
|
||||
|
||||
The same image, host, operations, warmup, loops, and sample order were used for
|
||||
both variants. Five raw samples per variant are retained; no failed sample was
|
||||
filtered. Baseline provider metadata reads were
|
||||
`1400,1400,1400,1400,1400`; candidate reads were
|
||||
`800,800,800,800,800`. Median reduction is `42.857142857142854%` for both
|
||||
instrumented calls and provider block reads, above the unchanged `25.0%` gate.
|
||||
|
||||
The focused cache model passes 64-worker one-owner publication, identical
|
||||
waiter bytes and typed failure, failed initialization without a half-published
|
||||
body, the 64 KiB entry limit, exact 1 MiB budget exhaustion fallback, invalidation,
|
||||
inflight close, reclaim, and zero resident bytes after cleanup. The decision
|
||||
is `GO`; source modification is now authorized only within the B19a write set.
|
||||
|
||||
## Evidence And Scope
|
||||
|
||||
Evidence is retained under
|
||||
`planning/pre15/evidence/20260817T171814Z-B19a/`. `GATE-attempt1` preserves the
|
||||
runner failure caused by the missing sample directory. `GATE-attempt2` is the
|
||||
authoritative GO replay with raw fixtures, oracle reports, cache-model output,
|
||||
sample JSON, aggregate TSV, commands, and cleanup manifest.
|
||||
|
||||
The authorized source/test write set is:
|
||||
|
||||
```text
|
||||
repo-pre-15/src/erofs_vnops.c
|
||||
repo-pre-15/src/inode.c
|
||||
repo-pre-15/src/internal.h
|
||||
repo-pre-15/src/xattr.c
|
||||
repo-pre-15/tests/pre15/cases/B19a-xattr-cache.sh
|
||||
repo-pre-15/tests/pre15/fixtures/B19a-*
|
||||
```
|
||||
|
||||
No QEMU or production source was touched by this Stage0 gate. B36 and all
|
||||
other execution units remain out of scope.
|
||||
|
||||
## B19a Acceptance Addendum
|
||||
|
||||
B19a subsequently implemented the authorized per-vnode xattr body/shared-ID
|
||||
cache within the declared write set. The focused FreeBSD 15.0-RELEASE-p8
|
||||
exact-ABI run passed first, concurrent, and repeated xattr reads; symmetric
|
||||
`EINTEGRITY` results for all three damaged images; normal and forced unmount;
|
||||
cache invalidation and reclaim; KLD unload; guest mount/md cleanup; target and
|
||||
runner cleanup; and an empty dmesg delta. The runner retained the original
|
||||
1200-second case deadline, focused command timeouts, 64 KiB body limit, 1 MiB
|
||||
mount budget, and 25 percent G05 threshold. The final evidence is under
|
||||
`planning/pre15/evidence/20260817T193130Z-B19a-final/`.
|
||||
@@ -0,0 +1,43 @@
|
||||
# P15-027 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B36 is `STOP-NO-SOURCE`.
|
||||
|
||||
G07 is evaluated per architecture against frozen BASE
|
||||
`4683579dabc57b0c9aaf5762e13ecc2a0ec3f8f9`. The mandatory audit set is
|
||||
arm64, riscv64, and i386. i386 is the real FreeBSD 32-bit target: the
|
||||
available FreeBSD source contains its machine headers and the pinned Clang
|
||||
toolchain contains the x86 backend. Source/toolchain availability is not
|
||||
native runtime evidence.
|
||||
|
||||
The inventory-first gate finds no declared same-architecture FreeBSD runtime
|
||||
for arm64, riscv64, or i386. The host is Linux/x86_64. An emulator binary,
|
||||
x86_64 guest, Linux execution, cross compilation, static layout output, or a
|
||||
runtime from another candidate cannot satisfy this condition. Missing native
|
||||
runtime is a per-architecture `STOP`, not `INFRA_BLOCKED`, and no architecture
|
||||
can borrow another architecture's result.
|
||||
|
||||
Because cross-only results cannot change any current decision, dual
|
||||
`WITH_ZSTDIO=0/1` KMOD builds and layout/unaligned/endian probes are
|
||||
`NOT_RUN` for all three architectures. The gate still verifies the frozen
|
||||
EROFS source tree, selected planning and probe hashes, FreeBSD source identity
|
||||
and architecture headers, compiler identity and target backends, and exact
|
||||
input-recorded Makefile relaxation. That patch is applied only to an owned
|
||||
temporary Makefile copy. The production `src/Makefile` remains byte-identical
|
||||
to BASE and retains the amd64-only error.
|
||||
|
||||
For a future rerun, each architecture has an independent native runner slot.
|
||||
A declaration must pass a bounded preflight reporting matching FreeBSD
|
||||
`uname -s`, architecture-specific `uname -m` and `uname -p`, and cleanup.
|
||||
Only then does the gate create a frozen temporary source copy, apply the sole
|
||||
recorded Makefile patch, build both KMOD configurations, record sizes and
|
||||
`nm -u`, and compile the layout and unaligned little-endian probes. The same
|
||||
runner must then load and unload both exact module hashes and record Plain,
|
||||
LZ4, LZMA, and Zstd reads. It must also prove running-kernel `options ZSTDIO`
|
||||
capability and exact disabled `EOPNOTSUPP`. Every operation carries argv,
|
||||
deadline, exit, target marker, cleanup, stdout/stderr, and hashes. A candidate
|
||||
is GO only when its own cross and native records both pass.
|
||||
|
||||
This decision does not authorize any B36 allowlist entry. No production
|
||||
source, B36 case, B36 probe, QEMU run, K build, feature suite, or smoke suite
|
||||
is created or run. Protected PID 26318, port 9222, and the shared base image
|
||||
are outside the gate and are not addressed.
|
||||
@@ -0,0 +1,51 @@
|
||||
# P15-030 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B37a is `STOP-NO-SOURCE`.
|
||||
|
||||
G08 is replayed against frozen BASE
|
||||
`3e1d26a53eef30ecadc3407444d214feac861cb4`. P15-030 may proceed only if all
|
||||
four conditions pass: an existing diagnostic or operational consumer, bounded
|
||||
atomic counters, a FreeBSD 15 native `sysctl_ctx` lifecycle that closes every
|
||||
required teardown path, and a stable privileged-read ABI that leaks no
|
||||
unauthenticated metadata.
|
||||
|
||||
The consumer condition is evaluated first because no prototype can create its
|
||||
own justification. The bounded inventory covers all 3,206 tracked paths under
|
||||
`repo-pre-15` and `planning/pre15` at BASE, without reading
|
||||
`planning/pre15/introduction.md` or treating this addendum as evidence. It
|
||||
finds 54 broad sysctl/sysfs references: 31 planning or audit records, one
|
||||
historical evidence record, 19 test-only paths, and three project reports or
|
||||
documents. There are zero production or operations paths and zero qualifying
|
||||
consumer declarations.
|
||||
|
||||
A qualifying future declaration must use schema
|
||||
`pre15-p15-030-consumer-v1`, identify a versioned diagnostic or operational
|
||||
consumer in production use, name its owner, workflow, deployment reference,
|
||||
privileged-read access mode, and consumed signals, and bind a tracked non-test
|
||||
implementation by path and SHA-256. The implementation must actually invoke
|
||||
sysctl and reference each declared signal. A hypothetical future user, Linux
|
||||
sysfs analogy, generic observability value, test script, or gate prototype is
|
||||
rejected. If a declaration appears, this STOP-only run refuses false GO and
|
||||
requires the FreeBSD 15 native lifecycle prototype before source authorization.
|
||||
|
||||
The first condition is `STOP`, so the bounded atomic-counter prototype,
|
||||
FreeBSD 15 parse-failure/normal-unmount/forced-unmount/delayed-handler/
|
||||
`sysctl_ctx_free`-failure lifecycle work, and permissions/ABI/leak probes are
|
||||
all `NOT_RUN`. No host model is reported as native evidence and no prototype,
|
||||
KLD, QEMU process, feature test, or smoke test is built or run.
|
||||
|
||||
P15-068 and B37b also close as `STOP` / `STOP-NO-SOURCE` because the plan
|
||||
explicitly requires the P15-030 transport. This is capability dependency
|
||||
closure, not an independent decision about UUID or volume-label formatting.
|
||||
The identity oracle is `NOT_RUN`; no P15-068 gate addendum and no second sysctl
|
||||
lifecycle are created.
|
||||
|
||||
The committed replay evidence is recorded under
|
||||
`planning/pre15/evidence/20260816T041649Z-G08-P15-030/`. The gate owns one
|
||||
temporary directory, uses a 60-second internal timeout plus the recorded outer
|
||||
timeout, records argv, scope/source/addendum hashes, result, and cleanup, and
|
||||
rejects an existing output directory.
|
||||
|
||||
No production source, B37a/B37b case, fixture, or empty commit is created.
|
||||
Protected PID 26318, port 9222, and the immutable base image are outside the
|
||||
gate and are not addressed or hashed.
|
||||
@@ -0,0 +1,45 @@
|
||||
# P15-031 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B38 is `STOP-NO-SOURCE`.
|
||||
|
||||
G08 is replayed against frozen BASE
|
||||
`0f696ad1e2c6628022d02ce52d07eb66704769dd`. P15-031 may proceed only if all
|
||||
five conditions pass: an existing project diagnostic consumer that has
|
||||
actually captured the complete predeclared mount/map/vget/xattr/decode/cache
|
||||
schema through FreeBSD DTrace/SDT or a justified KTR path; no pointer,
|
||||
credential, or unauthenticated metadata leakage; an owned-temp FreeBSD 15
|
||||
prototype with exact fields/counts and closed failure/detach/unload lifecycle;
|
||||
disabled `WITH_ZSTDIO=0/1` builds with no new undefined symbols; and a 10-run
|
||||
hot-path median regression of at most 3% with retained interleaved controls.
|
||||
|
||||
The consumer condition is evaluated first because neither a gate prototype nor
|
||||
a proposed B38 test can create its own project need. The bounded inventory
|
||||
covers all 3,243 tracked paths under `repo-pre-15` and `planning/pre15` at
|
||||
BASE, without reading `planning/pre15/introduction.md` or treating this
|
||||
addendum as evidence. It finds 33 native-tracing references: 16 planning or
|
||||
audit records, three historical evidence files, 10 test-only paths, and four
|
||||
reports or documents. There are zero production/operations paths, zero
|
||||
consumer manifests, and zero qualifying consumers.
|
||||
|
||||
A future declaration uses schema `pre15-p15-031-consumer-v1` under
|
||||
`repo-pre-15/diagnostics/`. It binds a versioned production implementation and
|
||||
actual FreeBSD 15 capture by path and SHA-256, identifies owner/workflow/
|
||||
deployment, records privileged access and DTrace/SDT or justified KTR
|
||||
transport, binds the complete event-schema hash, and records a positive count
|
||||
for every event. The gate rejects a hypothetical maintainer, Linux
|
||||
tracepoints, generic usefulness, a proposed test, its own prototype, or merely
|
||||
installed `dtrace`. If an approved declaration appears, this STOP-only version
|
||||
refuses false GO and requires the remaining native prototype, privacy, build,
|
||||
and benchmark stages before source authorization.
|
||||
|
||||
The first condition is `STOP`, so privacy execution, prototype generation,
|
||||
`WITH_ZSTDIO=0/1` builds, undefined-symbol comparison, the 10-run benchmark,
|
||||
D/H/K0/K1, targeted QEMU TC178, full feature, and smoke are all `NOT_RUN`.
|
||||
The gate's seven decision controls prove that GO is emitted only when all five
|
||||
conditions are `PASS`; no benchmark samples or later-stage metrics are
|
||||
fabricated.
|
||||
|
||||
No `src/erofs_trace.h`, trace callsite, `src/Makefile` change,
|
||||
`tests/pre15/cases/B38-trace.sh`, source commit, or empty commit is created.
|
||||
Protected PID 26318, port 9222, and the immutable base image are outside this
|
||||
STOP path and are not addressed or hashed.
|
||||
@@ -0,0 +1,106 @@
|
||||
# P15-032 / G09 vnode-backed image gate
|
||||
|
||||
## Decision rule
|
||||
|
||||
This gate is source-preparatory only. It does not link its model into EROFS and
|
||||
does not authorize B39 merely because a declared state sequence looks safe. It
|
||||
pins and extracts the relevant FreeBSD 15 vnode, pager, mount, GEOM, md(4),
|
||||
nullfs, unionfs, tarfs, and deadfs contracts, compiles an owned-temporary C
|
||||
lifecycle model generated from `P15-032-input.json`, and rejects adversarial
|
||||
false-GO mutations.
|
||||
|
||||
The runner exits with:
|
||||
|
||||
* `0`: gate GO;
|
||||
* `10`: gate STOP;
|
||||
* `20` or another nonzero value: runner failure;
|
||||
* `124`: absolute gate timeout.
|
||||
|
||||
All phases have absolute deadlines. The generated C source and its output are
|
||||
copied into the requested evidence directory; the temporary executable is
|
||||
removed by the runner trap.
|
||||
|
||||
## Closeable local vnode contract
|
||||
|
||||
The pinned FreeBSD sources support a coherent local lifecycle:
|
||||
|
||||
1. Use an explicit `vnode:/absolute/path` tag; GEOM remains explicit or legacy
|
||||
GEOM syntax. A mount and all `device.N` sources use one backend kind.
|
||||
2. Resolve with `namei`, require `VREG`, retain vnode identity with
|
||||
`vn_open_vnode(FREAD)`, retain the mounter credential with `crhold`, and use
|
||||
that credential for every source `VOP_READ`.
|
||||
3. Apply `VOP_SET_TEXT` before first I/O. The default write-count contract
|
||||
rejects existing or later writers with `ETXTBSY`; retain a size snapshot and
|
||||
convert a short source read into `EIO`. Rename or pathname replacement does
|
||||
not change the held vnode identity.
|
||||
4. Read synchronously into `UIO_SYSSPACE` under a source range lock and source
|
||||
vnode lock. FreeBSD's old vnode-pager fallback drops the VM object write
|
||||
lock before `VOP_READ`, so no user-buffer pager fault is introduced by this
|
||||
read shape.
|
||||
5. Register the source mount with `vfs_register_upper_from_vp` before first I/O.
|
||||
On unmount, reject new I/O, drain delayed and in-flight completions, `vflush`,
|
||||
unregister the upper mount, unset text, close the vnode, release the held
|
||||
credential, and then release the final mount-private reference. A forced
|
||||
dead source returns `ENXIO` rather than silently changing identity.
|
||||
6. Keep GEOM open/read/close and vnode open/read/close as disjoint tagged-union
|
||||
branches. This preserves the existing GEOM and multidevice behavior.
|
||||
|
||||
The generated model checks this order and independently removes each local
|
||||
invariant to ensure that every mutation is rejected.
|
||||
|
||||
## Blocking FreeBSD contract
|
||||
|
||||
The required pre-I/O self and ancestor check is transitive across VFS and GEOM,
|
||||
not only across pathname aliases:
|
||||
|
||||
```
|
||||
regular source vnode
|
||||
-> source filesystem
|
||||
-> md(4) GEOM provider
|
||||
-> md_s.s_vnode.vnode
|
||||
-> another filesystem vnode
|
||||
```
|
||||
|
||||
The final identity edge is not available through a generic, identity-preserving
|
||||
FreeBSD API:
|
||||
|
||||
* `VOP_GETLOWVNODE` exposes vnode-stack aliases such as nullfs and unionfs, but
|
||||
it does not traverse a filesystem's GEOM storage dependency.
|
||||
* `vfs_register_upper_from_vp` pins the immediate source vnode mount and orders
|
||||
its unmount, but it does not register hidden GEOM-to-vnode backing edges.
|
||||
* `md(4)` stores the held backing vnode in the private `struct md_s` defined in
|
||||
`md.c`. Its GEOM object exposes only `void *softc`; dump configuration exposes
|
||||
a pathname, not a held vnode identity.
|
||||
* Re-resolving that pathname fails the rename/replace invariant. Casting
|
||||
`g_geom.softc` to a copied private `struct md_s` is an undocumented,
|
||||
class-specific dependency and does not cover other filesystem-private or
|
||||
GEOM-private file-backed providers.
|
||||
|
||||
Consequently a visible-only oracle can approve all vnode, credential, pager,
|
||||
resize, and unmount checks while missing the hidden backing-vnode ancestor. The
|
||||
gate includes that case as an adversarial false-GO control. There is no sound
|
||||
place to return the required single cycle errno (`EDEADLK`) because the cycle
|
||||
identity cannot first be discovered.
|
||||
|
||||
## Result
|
||||
|
||||
`P15-032` is **STOP** and B39 is **STOP-NO-SOURCE**. Recursive I/O and its lock
|
||||
graph cannot be statically excluded for the requested regular-file source
|
||||
surface using documented generic FreeBSD interfaces. A safe future GO needs a
|
||||
new kernel dependency API that returns and pins transitive backing vnode
|
||||
identities, or an explicitly narrower feature contract whose permitted source
|
||||
filesystems have no hidden storage dependencies. Neither change is in B39's
|
||||
authorized write set.
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```sh
|
||||
repo-pre-15/tests/pre15/gates/P15-032.sh \
|
||||
--base bd5a09054e5cf89efd4db82aadb051f20b06ebf7 \
|
||||
--freebsd-src /work/build/freebsd-src \
|
||||
--output /absolute/owned/output/path
|
||||
```
|
||||
|
||||
No EROFS source, Makefile, feature documentation, B39 case, or B39 fixture is
|
||||
modified by this STOP addendum. D, H, K, Q, TC006, TC179, TC184, smoke, and the
|
||||
full feature suite are not run at the gate stage.
|
||||
@@ -0,0 +1,85 @@
|
||||
# P15-038 Stage0 Decision
|
||||
|
||||
Status: `GO`. B33 is authorized.
|
||||
|
||||
The authoritative frozen-BASE run is
|
||||
`planning/pre15/evidence/20260816T021736Z-G05-P15-038/` against
|
||||
`5d6755649a369498a9b257bb2d1d1e3496d5135e`. Its state model, hard-budget
|
||||
accounting, real codec oracle, eviction check, and owned cleanup all pass.
|
||||
|
||||
The gate compares the current LZMA-only admission policy with a test-only,
|
||||
codec-neutral single-entry decoded cache. Both variants execute the same 1,024
|
||||
deterministic random 4 KiB logical reads against the same 256 KiB payload for
|
||||
each of LZ4, LZMA, Deflate, and Zstd. Each variant has exactly five cold-cache
|
||||
samples; no sample may be discarded. The helper uses the frozen host
|
||||
liblz4/liblzma/zlib/libzstd libraries and performs real compression and full
|
||||
decode work. It contains no synthetic sleep.
|
||||
|
||||
This is an independent host codec-cost oracle. It can prove avoided codec work
|
||||
and byte correctness, but it is not guest vnode latency evidence and must not
|
||||
be reported as such. Provider I/O, map lookup, VOP dispatch, and guest kernel
|
||||
scheduling are outside its scope.
|
||||
|
||||
The state model preserves B32's exact key, one-owner, waiter, typed-failure,
|
||||
retry, and no-cache fallback rules. It additionally freezes mount-cache then
|
||||
global-budget lock order, reservation-before-decode accounting, codec-neutral
|
||||
work/size admission, disabled policy, global exhaustion, ready eviction,
|
||||
inflight reclaim refusal, successful reclaim, unmount drain, and key reuse.
|
||||
Reserved plus resident decoded bytes are charged to the same hard budget.
|
||||
|
||||
G05 is GO only if the state model closes, all current/candidate hashes match,
|
||||
eviction-before/after SHA-256 matches, every candidate sample stays within the
|
||||
fixed budget, and at least two codecs improve median latency by 10 percent or
|
||||
more. Any missing sample, correctness mismatch, lifecycle gap, or budget
|
||||
overflow is STOP for P15-038 only.
|
||||
|
||||
## Result
|
||||
|
||||
All five current and five candidate samples are retained for each codec. The
|
||||
median current/candidate latencies and improvements are:
|
||||
|
||||
| Codec | Current median | Candidate median | Improvement |
|
||||
|---|---:|---:|---:|
|
||||
| LZ4 | 44,988,337 ns | 6,583,335 ns | 85.367% |
|
||||
| LZMA | 7,278,779 ns | 7,286,634 ns | -0.108% |
|
||||
| Deflate | 186,791,959 ns | 6,102,297 ns | 96.733% |
|
||||
| Zstd | 20,355,035 ns | 6,236,635 ns | 69.361% |
|
||||
|
||||
Three codecs exceed the required 10 percent threshold. LZMA is the expected
|
||||
control because both current and candidate policies admit it; its negative
|
||||
0.108 percent delta is retained and is not excluded or rewritten.
|
||||
|
||||
Every candidate sample charges exactly 262,144 resident bytes against the
|
||||
262,144-byte mount budget. The state model reaches the 524,288-byte global
|
||||
limit with two mounts, proves a third mount's synchronous no-cache fallback,
|
||||
reclaims one reservation, retries successfully, and returns to zero bytes.
|
||||
It also passes 16-thread success and typed-failure waves, ready eviction,
|
||||
inflight reclaim refusal, key reuse, policy disable, low-work/oversize bypass,
|
||||
and unmount drain. The real Deflate decode before and after eviction has
|
||||
SHA-256 `5d3c21088380524a78c52b067d47a93117c5385464c5dfc83e8de598119511bb`.
|
||||
|
||||
No QEMU process was started by this pre-source gate. No guest vnode latency is
|
||||
claimed. No production source, B32 correctness path, B32 QEMU runner, protected
|
||||
PID 26318, port 9222, or shared base image was touched. B33 may now execute its
|
||||
exact write set and acceptance matrix.
|
||||
|
||||
## B33 Execution
|
||||
|
||||
B33 source/test commit `bc56f830918b76029871b60cca2e53992de70a2e`
|
||||
implements codec-neutral decoded-work/size admission with fixed hard mount and
|
||||
global budgets, loader configuration/disable controls, four-codec accounting,
|
||||
FreeBSD `vm_lowmem` reclaim, eviction, unmount release, and synchronous
|
||||
no-cache fallback. It changes only `src/internal.h` and `src/zdata.c` in the
|
||||
production tree and preserves the B32 key/inflight/failure contract.
|
||||
|
||||
D, authoritative H `20260816T025825Z-host-B33-cache-policy-1393732-0`, and
|
||||
FreeBSD 15 cross-KLD builds with zstdio0 and zstdio1 pass. The final H-tested
|
||||
seven-path source/test tree is byte-identical to the committed tree. Q
|
||||
TC168-cache-inflight is `INFRA_BLOCKED`: guest SSH was not ready at the exact
|
||||
absolute 300-second deadline, so no guest source, case target, KLD load, vnode
|
||||
latency, or guest PASS is claimed. Owned PID 1389807, overlay, and port 33537
|
||||
were cleaned; the protected process, port, and base metadata are unchanged.
|
||||
|
||||
The Q attempt predates the final replacement-order and policy-bypass-accounting
|
||||
changes and did not reach the DUT. Full correspondence details and exact hashes
|
||||
are in `planning/pre15/evidence/20260816T023315Z-B33/VERDICT.md`.
|
||||
@@ -0,0 +1,44 @@
|
||||
# P15-045 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B35 is `STOP-NO-SOURCE`.
|
||||
|
||||
G07 is replayed against frozen BASE
|
||||
`13974efc00c31d8c13c8dccb7c65a82adafcbff6`. Its first mandatory condition
|
||||
is a concrete, versioned support/deployment manifest in existing project
|
||||
evidence that identifies deployment targets and explicitly requires Zstd to
|
||||
be enabled by default. General codec availability, prior Zstd test success,
|
||||
Linux defaults, and maintainer preference are intentionally nonqualifying.
|
||||
|
||||
The gate inventories every tracked path in the frozen
|
||||
`planning/pre15/evidence` tree (tree object
|
||||
`3ecce7a124d153638853ab5d897126c769125309`, 2,560 paths), locates every text
|
||||
record containing Zstd/Zstandard, and reviews records with deployment,
|
||||
support, manifest, policy, default, or requirement signals. It accepts either
|
||||
a structured JSON manifest or explicit text manifest headers, but requires a
|
||||
manifest kind, version, nonempty deployment/support targets, and an
|
||||
affirmative Zstd-default requirement together. The replay finds 596 Zstd text
|
||||
records and 206 demand-signal candidates; no record meets that contract.
|
||||
|
||||
The missing deployment-demand prerequisite determines STOP before runtime or
|
||||
build work. The disabled exact-`EOPNOTSUPP` runtime check, enabled real Zstd
|
||||
EROFS read, FreeBSD kernel `ZSTDIO` symbol/capability check, and KLD size delta
|
||||
measurement are therefore `NOT_RUN`; none is reported as PASS. In particular,
|
||||
the gate does not claim or attempt to load a generic dependency KLD. A
|
||||
false-GO guard requires every G07 condition to be PASS.
|
||||
|
||||
The frozen source is checked only to preserve the current policy boundary:
|
||||
`src/Makefile` contains exactly one `WITH_ZSTDIO?= 0` default, the disabled
|
||||
stub returns `EOPNOTSUPP`, and the documentation names kernel
|
||||
`options ZSTDIO`. These are static observations, not substitutes for the
|
||||
runtime conditions omitted after the prerequisite STOP.
|
||||
|
||||
The committed replay evidence is recorded under
|
||||
`planning/pre15/evidence/20260816T033449Z-G07-P15-045/`. The gate owns one
|
||||
temporary directory, uses a 90-second internal absolute timeout plus the
|
||||
recorded outer timeout, records argv, source/candidate hashes, exit status,
|
||||
and cleanup, and rejects an existing output directory.
|
||||
|
||||
No production source, B35 case, B35 fixture, QEMU process, full feature suite,
|
||||
or smoke suite is run or changed. Protected PID 26318, port 9222, and the
|
||||
shared base image are outside the gate. The supported policy remains opt-in
|
||||
`WITH_ZSTDIO=1`, with default `WITH_ZSTDIO?=0`.
|
||||
@@ -0,0 +1,74 @@
|
||||
# P15-052 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B20 is complete as `STOP-NO-SOURCE`; B21 was not started.
|
||||
|
||||
The authoritative G06 replay uses frozen BASE
|
||||
`ca7bb4fe6b33e4a1bdf423801134b0ed6bda86dd`. It verifies the exact current
|
||||
FreeBSD and Linux source hashes, the FreeBSD amd64 `PAGE_SHIFT=12` contract,
|
||||
signed 64-bit `off_t`, and GEOM's `off_t mediasize` before evaluating every
|
||||
listed branch.
|
||||
|
||||
## Exact Branch Result
|
||||
|
||||
All twelve proposed on-disk arithmetic branches have unique source sites, but
|
||||
none has a target marker reachable from one validated on-disk field mutation.
|
||||
The current source text returns positive `EOVERFLOW` at those defensive sites;
|
||||
the proposed mapping would be positive `EINTEGRITY`. Linux has no matching
|
||||
checked branches in these functions, so its relevant semantic mapping is
|
||||
negative `-EFSCORRUPTED`, not a textual negative copy of the FreeBSD return.
|
||||
|
||||
The decisive counterexample to the supplied READY prototype is
|
||||
`xattr.metadata.header_add`. The prototype directly mutates the local
|
||||
`aligned_off` value. The real helper first rejects input above
|
||||
`UINT64_MAX - 3`, then rounds to four bytes. The greatest surviving aligned
|
||||
offset is therefore `UINT64_MAX - 3`; adding the two-byte header cannot
|
||||
overflow. The named branch cannot be independently reached.
|
||||
|
||||
The other prototype vectors likewise inject values outside current provenance:
|
||||
mounted image bytes are bounded by GEOM's signed `off_t mediasize`; inode size
|
||||
is bounded by `OFF_MAX`; decoded physical blocks are at most 48 bits;
|
||||
`blkszbits` is at most 12; prefix start and shared IDs are 32-bit. These bounds
|
||||
prevent each proposed shift, add, alignment, and index overflow before the
|
||||
listed target.
|
||||
|
||||
## Preserved Semantics
|
||||
|
||||
The replay separately freezes corruption, unsupported, provider I/O, EOF, and
|
||||
short-read behavior. Disk/backing range contradictions remain positive
|
||||
`EINTEGRITY`; exact zero-length EOF remains success; provider `EIO` and media
|
||||
`ENXIO` remain exact; unsupported xattr layout remains positive
|
||||
`EOPNOTSUPP`; allocation remains positive `ENOMEM` and outside B20. Linux
|
||||
counterparts retain negative errno or `PTR_ERR` propagation.
|
||||
|
||||
The nominal `erofs_xattr_read_backing()` `off > INT64_MAX` positive
|
||||
`EOVERFLOW` site is also not reachable for a mounted primary provider: the
|
||||
preceding range check requires `off <= backing_size`, while mount validation
|
||||
requires `backing_size <= INT64_MAX`. This site remains unchanged because a
|
||||
STOP decision has no source diff.
|
||||
|
||||
## Atomic Decision
|
||||
|
||||
G06 requires every listed branch to be independently reachable. One missing
|
||||
branch stops all of P15-052; this replay finds twelve missing target markers.
|
||||
No `data.c` or `xattr.c` errno is changed, no B20 case/fixture is created, and
|
||||
no candidate replay or QEMU run can cure a host-proven reachability failure.
|
||||
The full feature suite was not run.
|
||||
|
||||
The authoritative command was:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 tests/pre15/gates/P15-052.sh \
|
||||
--base ca7bb4fe6b33e4a1bdf423801134b0ed6bda86dd \
|
||||
--output OWNED_OUTPUT
|
||||
```
|
||||
|
||||
It exited 1 because a valid gate `STOP` is not `GO`. Two fresh output
|
||||
directories were byte-identical. The initial replay produced result SHA256
|
||||
`37280545d8ef5a6b87c7b9d536939513a1bbac8e4e4b2389e84f5ca77e1aa522`,
|
||||
branch-ledger SHA256
|
||||
`8024a2cb6b43bd10fbcf446cf8cf44de37f1f9d6df25718c641cb9db4c257169`,
|
||||
and preservation-ledger SHA256
|
||||
`d17e05b8df43ea5173bed6e58d7431b37a7a9c4a143e07717b543efcb54ecc66`.
|
||||
|
||||
B21 is not authorized because the execution request requires B20 PASS before
|
||||
B21. Wave16 is therefore not ready from this serial chain.
|
||||
@@ -0,0 +1,13 @@
|
||||
# P15-057 Stage0 Decision
|
||||
|
||||
Status: `GO`; B17 is complete.
|
||||
|
||||
The B17 fixture gate contains 25 reproducible EROFS images and independently
|
||||
freezes all legal results and damaged positive FreeBSD errnos. The source
|
||||
commit `433cf4ec66478b65b291ec5b21a0bf6d806bd14f` preserves the raw xattr filter
|
||||
feature declaration, saves its reserved byte, and gates the current filter
|
||||
format only at the ACL use site. Reserved values 0, 1, and 255 and feature
|
||||
present/absent combinations pass host and minimal FreeBSD 15 QEMU replay.
|
||||
|
||||
Evidence is in `planning/pre15/evidence/20260814T203439Z-B17/`. This decision
|
||||
does not authorize the separate cache, Bloom, or ordering batches.
|
||||
@@ -0,0 +1,13 @@
|
||||
# P15-058 Stage0 Decision
|
||||
|
||||
Status: `GO`; B17 is complete.
|
||||
|
||||
The B17 corpus separately covers inline names, shared names, and long-prefix
|
||||
infixes containing embedded NUL, with independently frozen `EINTEGRITY` (97)
|
||||
reject points. It also covers legal ACL empty-suffix names and short/long
|
||||
name-index failures. Source commit
|
||||
`433cf4ec66478b65b291ec5b21a0bf6d806bd14f` rejects only the length-delimited
|
||||
embedded-NUL formats and retains the FreeBSD namespace and extattr ABI.
|
||||
|
||||
Evidence is in `planning/pre15/evidence/20260814T203439Z-B17/`. This decision
|
||||
does not include xattr cache, Bloom, or call-order changes.
|
||||
@@ -0,0 +1,89 @@
|
||||
# P15-062 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B26 is `STOP-NO-SOURCE`; no production source, B26 case, or
|
||||
B26 fixture is authorized.
|
||||
|
||||
The decision is bound to DUT BASE
|
||||
`205a90465edb64e83ba44aaacac9bedad4cbe905`, FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, and exact upstream erofs-utils
|
||||
commits for v1.4, v1.7, and v1.8.6. The authoritative gate evidence and final
|
||||
script/input hashes are recorded below and in the G04 evidence commit.
|
||||
|
||||
The later B26 terminal review is recorded at
|
||||
`planning/pre15/evidence/20260817T-B26-terminal-review/VERDICT.md`.
|
||||
It retains `STOP_NO_SOURCE / NOT_TESTED` and adds secondary
|
||||
`TERMINAL_REVIEWED_NO_SOURCE`. It found the historical zero-tail shape to be
|
||||
reproducible, but did not establish that trailing zeros are format-mandated or
|
||||
that current FreeBSD rejects them.
|
||||
|
||||
## Authoritative Run
|
||||
|
||||
The gate ran from `/work/erofs-freebsd-pre` as:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-062.sh \
|
||||
--base 205a90465edb64e83ba44aaacac9bedad4cbe905 \
|
||||
--output planning/pre15/evidence/20260815T062257Z-G04-P15-062/gate-output
|
||||
```
|
||||
|
||||
It returned the gate-defined STOP exit status 1. Evidence is rooted at
|
||||
`planning/pre15/evidence/20260815T062257Z-G04-P15-062/`. The authoritative
|
||||
script SHA-256 is
|
||||
`6af503f1612eb42410f91a54fdc37481bae86a4419232c9de48c08bfa7ecee5d` and
|
||||
the input SHA-256 is
|
||||
`390202738ac006aba2514d27d3b0a19a0123a009601a26cac3b560a3dff388e5`.
|
||||
The result SHA-256 is
|
||||
`597466203edcaee6d163651a6d6a05e49dff24f39201234911f9753b29eebbe0`.
|
||||
|
||||
## Decision Rule
|
||||
|
||||
G04 permits P15-062 only if every normative and historical full LZ4 input uses
|
||||
the same exact-consumption rule. The B26 review found that the old fsck
|
||||
acceptance path uses `LZ4_decompress_safe_partial()` for legacy/no-0padding
|
||||
images, so that acceptance does not prove full physical consumption or format
|
||||
legality. The format sources contain no stored compressed-stream length or
|
||||
general trailing-zero rule. The current FreeBSD decoder accepts an all-zero
|
||||
remainder and rejects nonzero remainder bytes; no implementation defect was
|
||||
demonstrated.
|
||||
|
||||
## Reproducible Corpus
|
||||
|
||||
The gate builds three upstream mkfs generations from exact commits in an owned
|
||||
temporary directory. Each version twice generates the same fixed-time,
|
||||
fixed-UUID, root-owned, xattr-free legacy LZ4 image from the same deterministic
|
||||
1 MiB file. Matching `fsck.erofs --extract` accepts each image. The image,
|
||||
source, build tree, and binaries remain temporary and are not committed.
|
||||
|
||||
The independent parser reconstructs the complete file from two physical
|
||||
pclusters. The final extent has `m_plen=4096`, but its raw LZ4 stream reaches
|
||||
9,670 decoded bytes after consuming 48 bytes; the remaining 4,048 bytes are
|
||||
zero. This shape is byte-reproducible in v1.4, v1.7, and v1.8.6. The current
|
||||
FreeBSD decoder accepts the whole input and liblz4 accepts the 48-byte exact
|
||||
stream but rejects the block-sized input. The zero-tail shape is therefore a
|
||||
historical tool-compatible candidate, not a proven format-legal fixture.
|
||||
|
||||
## Partial and Corruption Controls
|
||||
|
||||
A separate v1.8.6 `-Ededupe` image contains two real noncompact
|
||||
`Z_EROFS_LI_PARTIAL_REF` records that share an LZ4 pcluster. The independent
|
||||
parser, liblz4 partial API, and frozen DUT callback agree on the 4,096- and
|
||||
5,594-byte prefixes. Corruption beginning after the 4,096-byte request remains
|
||||
undetected by that partial read but causes the same fixture's full decode to
|
||||
return positive `EINTEGRITY` (97), as required by G04. Truncation and nonzero
|
||||
tail controls also return 97; all output guards remain unchanged.
|
||||
|
||||
Production `zdata.c` ownership anchors show that metadata/physical input is
|
||||
released after every decoder return, failed decoded output is freed, and only
|
||||
successful output is published. The decoder itself allocates and owns no
|
||||
buffers. The gate's owned build/image directory is removed, and it does not
|
||||
start QEMU or touch protected PID 26318, port 9222, or the shared base image.
|
||||
|
||||
## Consequence
|
||||
|
||||
P15-062 remains STOP for Pre15 because B26 has no authorized production source,
|
||||
case, or fixture. `src/decompressor_lz4.c`,
|
||||
`tests/pre15/cases/B26-lz4-input.sh`, and `tests/pre15/fixtures/B26-*` remain
|
||||
unchanged or absent as applicable. B26 acceptance D, exact-ABI build, TC167
|
||||
QEMU, and the full feature suite are not run because no implementation error
|
||||
was demonstrated. The secondary B26 status is
|
||||
`TERMINAL_REVIEWED_NO_SOURCE`.
|
||||
@@ -0,0 +1,75 @@
|
||||
# P15-076 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B29 is `STOP-NO-SOURCE`.
|
||||
|
||||
The gate is bound to frozen DUT BASE
|
||||
`3e9bc3f03ba9c39c38cc40f2f08eb6e769557f55` and FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`. Three host attempts are retained:
|
||||
|
||||
- `20260815T170841Z-G05-P15-076`: `RUNNER_FAIL`, FreeBSD headers shadowed
|
||||
glibc headers during host compilation.
|
||||
- `20260815T170931Z-G05-P15-076`: `RUNNER_FAIL`, the Deflate oracle compared
|
||||
one selected extent with the complete source payload.
|
||||
- `20260815T171051Z-G05-P15-076`: the runner returned 0, but final review
|
||||
rejects its local `GO` because mandatory state-model conditions are not
|
||||
closed.
|
||||
|
||||
## Last Attempt Command
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-076.sh \
|
||||
--base 3e9bc3f03ba9c39c38cc40f2f08eb6e769557f55 \
|
||||
--output planning/pre15/evidence/20260815T171051Z-G05-P15-076/gate-output
|
||||
```
|
||||
|
||||
The command returned 0 in three seconds. The gate script SHA-256 is
|
||||
`1d2cc18de150c8bdeb4fa8d284ab345f9ec4249c2ba1b50e1badbe7f942b42dc`,
|
||||
the input SHA-256 is
|
||||
`30497cf86785c367dcd4a3d6889ba6a6302f6f133d68e4af31d984a1031e0058`,
|
||||
and the result SHA-256 is
|
||||
`ac007afc4ad5a97bb1561888105c67612d3eea5427f77c54a858bede4c86e0a3`.
|
||||
|
||||
## Benefit Result
|
||||
|
||||
The last attempt regenerates the frozen B28 EROFS fixtures in owned temporary
|
||||
storage and decodes the exact selected LZMA, Deflate, and Zstd extents. Input,
|
||||
expected output, and output buffers are outside the tracked allocator region.
|
||||
Baseline creates and destroys a context per decode; the prototype resets one
|
||||
context across 64 exact decodes. Seven samples are retained per mode.
|
||||
|
||||
| Codec | Baseline events | Reused events | Reduction | Measured peak |
|
||||
|---|---:|---:|---:|---:|
|
||||
| LZMA | 128 | 2 | 98.4375% | 28,504 B |
|
||||
| Deflate | 256 | 4 | 98.4375% | 39,928 B |
|
||||
| Zstd | 128 | 2 | 98.4375% | 95,992 B |
|
||||
|
||||
All tracked baseline backend allocator events are context lifecycle events, so
|
||||
the measured share is 100 percent and passes the 10 percent threshold. All
|
||||
three event reductions pass the 25 percent threshold. Exact output and
|
||||
balanced allocation/free counts pass. CPU remains diagnostic: Deflate is
|
||||
1.30 percent faster, LZMA is 10.20 percent slower, and Zstd is 15.35 percent
|
||||
faster by median per-decode time; the LZMA regression is retained.
|
||||
|
||||
## STOP Review
|
||||
|
||||
G05 requires both the benefit threshold and a complete pre-source state model.
|
||||
The retained runner does not establish a hard memory limit: its 329,616-byte
|
||||
mount and 2,636,928-byte global calculations use peaks from representative
|
||||
streams. In particular, its Zstd prototype sets `ZSTD_d_windowLogMax` to 16,
|
||||
while the frozen DUT accepts values through 20. The measured 95,992-byte Zstd
|
||||
peak therefore is not a hard bound for the production-supported range. LZMA is
|
||||
also sampled with a 65,536-byte dictionary while the DUT accepts up to 8 MiB.
|
||||
|
||||
The state model also does not execute a global-exhaustion transition. It sets
|
||||
`global_owned` and `mount_owned` to the mount limit of two and selects fresh
|
||||
allocation because the mount is full; the independent global limit of 16 is
|
||||
never reached. Text describing global exhaustion cannot replace that missing
|
||||
assertion. Therefore the hard-cap and global-exhaustion requirements are not
|
||||
closed, and the runner-local `GO` cannot authorize source work.
|
||||
|
||||
No threshold, sample, or result is changed to force a decision. Per G05, one
|
||||
failed mandatory condition makes P15-076 `STOP`; B29 is recorded
|
||||
`STOP-NO-SOURCE`. No production `src/**`, B29 case, fixture, or helper was
|
||||
changed. B29 H/K/Q acceptance, QEMU, and the full feature suite were not run.
|
||||
The hard-timeout D check passed. Owned temporary cleanup passed; protected PID
|
||||
26318, port 9222, and the shared base image were untouched.
|
||||
@@ -0,0 +1,95 @@
|
||||
# P15-081 Stage0 Decision
|
||||
|
||||
Status: `GO`. B11 is authorized; no production source was modified by this
|
||||
decision.
|
||||
|
||||
The authoritative G11 replay uses frozen B25 BASE
|
||||
`e2e3fb86b6fffcb01d6fd29c17dd95628ad070de`, FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, and
|
||||
`mkfs.erofs (erofs-utils) 1.8.6`. The gate script and input SHA256 values are
|
||||
`6215a3005214ba8d25dacd63e039320a0c63308d2334b5faff99a3927cad7d2e`
|
||||
and `a887fad56927545adb48462b770100d1e64b22b32554ed8ffad14c72b8febfc3`.
|
||||
|
||||
## Real Disk and Normal Entrypoint
|
||||
|
||||
The gate independently materializes a deterministic source tree containing
|
||||
regular, directory, character-device, block-device, FIFO, socket, symlink,
|
||||
and two hardlink names. It invokes mkfs twice with fixed UUID, time, ownership,
|
||||
worker count, xattr policy, and inline-data policy. It also fixes and restores
|
||||
the process umask and explicitly sets every source-node mode. Complete
|
||||
replays under outer umask `022` and `077`, including both seed generations in
|
||||
each replay, are byte-identical.
|
||||
|
||||
The gate parses the actual superblock, checksum range, root inode, inline root
|
||||
directory, 12-byte dirents, NIDs, and compact inode modes without using DUT
|
||||
helpers. Every derived image changes one real dirent byte and recomputes the
|
||||
superblock CRC32C. `dump.erofs --ls --path=/` observes the mutated on-disk
|
||||
`file_type`, while `dump.erofs --path=/NAME` reaches the same NID and reports
|
||||
the inode kind from its mode. This gives 13 normal namespace resolutions from
|
||||
real disk fields: eight known mismatches and five forward-compatibility cases.
|
||||
|
||||
All eight known mismatches are checksum-valid, fsck-clean images and yield
|
||||
positive FreeBSD `EINTEGRITY` in the independent candidate oracle. Type zero,
|
||||
nonzero dirent reserved bytes, and out-of-range type 8/255 remain accepted by
|
||||
the DUT policy and candidate oracle. erofs-utils fsck separately rejects 8/255;
|
||||
the evidence records that as `policy-reject` rather than falsely claiming
|
||||
fsck-clean. P15-093 already freezes the FreeBSD behavior for these extension
|
||||
values as `DT_UNKNOWN`, so fsck's stricter userspace policy does not override
|
||||
the G11 compatibility boundary.
|
||||
|
||||
## Cache and Lock Boundary
|
||||
|
||||
`regular` and `regular-hard` are different namespace keys with the same real
|
||||
NID. The first normal lookup can instantiate the vnode; the second name misses
|
||||
that namecache key and reaches the existing `erofs_vget()` path, whose frozen
|
||||
body checks `vfs_hash_get()` before inode decode. Mutating only the second
|
||||
dirent to known directory type therefore provides the required cached-vnode
|
||||
trigger without adding a readdir-time vget.
|
||||
|
||||
The generated candidate patch adds no lock, vget, hash, or recursive lookup
|
||||
call. It reads immutable `vtype` after the existing child lookup, returns
|
||||
positive `EINTEGRITY` for a known mismatch, drops the locked child with
|
||||
`vput()`, and runs before `a_vpp` and namecache publication. Dotdot's existing
|
||||
`vn_vget_ino()` path explicitly bypasses the validator because root `..` can
|
||||
return the directory vnode itself; this preserves its parent-lock contract.
|
||||
The parent/child lock order, readdir cookies, and VFS/VOP entrypoints are
|
||||
unchanged. Readdir still contains no vnode lookup.
|
||||
|
||||
Linux supplies the format mapping: EROFS file type values match generic Linux
|
||||
`FT_*`, and Linux readdir maps those values with `fs_ftype_to_dtype()`. The
|
||||
candidate aligns that known-type mapping while retaining FreeBSD vnode types,
|
||||
the FreeBSD 15 `__enum_uint8(vtype)` ABI type, positive errno, VFS locks, and
|
||||
forward handling for unknown values.
|
||||
|
||||
## Replay Result
|
||||
|
||||
The authoritative command was:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 tests/pre15/gates/P15-081.sh \
|
||||
--base e2e3fb86b6fffcb01d6fd29c17dd95628ad070de \
|
||||
--output OWNED_OUTPUT
|
||||
```
|
||||
|
||||
It exits zero with `GO`: 14 generated images, eight known-match records
|
||||
including the hardlink alias, eight known mismatches, five compatibility
|
||||
cases, 13 normal entrypoint observations, one cached-vnode sequence, and 21
|
||||
compiled prototype records. Two fresh output directories are byte-identical. The fixture-set
|
||||
SHA256 is
|
||||
`b562a7e42e139b16f3ce399d585aa7c373a66aa478a084bfed67b2b2aa9f2bd3`.
|
||||
|
||||
Key immutable evidence SHA256 values are:
|
||||
|
||||
- `result.json`: `4ec8e053c60ae75ae2fc4580a3d820a0452cf519f6b85376953135e18a7ec0ec`
|
||||
- `oracle.json`: `932e558d3ead05572f38c89635bb10cae45393e42028031f81dfc7a56f2093f6`
|
||||
- `lock-ledger.json`: `e8c2e6ba797fbcc83d832af6583d3f74f344750f6897111e7fe501130e577c13`
|
||||
- `fixture-index.json`: `1a46b8ebfec16109c5d193001dc650a1b56000045e5d9e1e9b145fe7c5df9a16`
|
||||
- `candidate.patch`: `427097da9304f5bedb770be8cab5f589706d316fb18a152ca16cb9d0663713fd`
|
||||
- `prototype.c`: `1a295d18830c61a9708d465c3b1e415efb3ff8276100e4e32139bfa715195d8b`
|
||||
- `normal-entry.tsv`: `b2841448068f70633ed0c02d901177a639cfed150f0e1c58977cc6c7b1e7313e`
|
||||
- `SHA256SUMS`: `36b486617920b04ca87e88016e2fc0f519cda3a5f99dc675c9a89549615a02e3`
|
||||
|
||||
QEMU and the full feature suite were not run for this pre-source gate. The
|
||||
gate uses host-created real EROFS images, independent binary parsing, normal
|
||||
userspace namespace resolution, frozen DUT/FreeBSD control flow, and a
|
||||
compiled prototype that is not linked into the DUT KLD.
|
||||
@@ -0,0 +1,101 @@
|
||||
# P15-083 Stage0 Decision
|
||||
|
||||
Status: `GO`. G04 authorizes B27 for all three non-LZ4 codecs. The source batch
|
||||
must preserve the exact policies below and may not import the P15-062 LZ4 STOP
|
||||
rule.
|
||||
|
||||
The gate is bound to DUT BASE
|
||||
`68bbe94c44e35d53cec8ab55d007f40b01cf0502`, FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils 1.8.6, liblzma
|
||||
5.8.1, zlib 1.3.1, and libzstd 1.5.7.
|
||||
|
||||
## Authoritative Run
|
||||
|
||||
The gate ran from `/work/erofs-freebsd-pre` as:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-083.sh \
|
||||
--base 68bbe94c44e35d53cec8ab55d007f40b01cf0502 \
|
||||
--output planning/pre15/evidence/20260815T142600Z-G04-P15-083/gate-output
|
||||
```
|
||||
|
||||
It returned 0 and recorded `GO`. Evidence is rooted at
|
||||
`planning/pre15/evidence/20260815T142600Z-G04-P15-083/`. The authoritative
|
||||
script SHA-256 is
|
||||
`6847541266b0668ad12442ffb54b67a772a29ed8ebe6fba0e1e25214db16b2c2`, the
|
||||
input SHA-256 is
|
||||
`b3c71b4ae03c6f9511246813952aab3178a1451433ece96f04562ec7cc6c1d1e`, and
|
||||
the result SHA-256 is
|
||||
`b9431b3819d64cdf940dff05ce7bc0e0bdf44c3ec647c90592052af5f7b3e544`.
|
||||
|
||||
## Decision Rule
|
||||
|
||||
P15-083 is GO only if LZMA, Deflate, and Zstd each have a reproducible real
|
||||
EROFS fixture, an independent consumed-byte oracle, and a codec-specific policy
|
||||
that distinguishes EROFS leading zero padding from unread nonzero bytes. Any
|
||||
missing codec oracle, legal image rejected by the proposed full-stream policy,
|
||||
or inability to distinguish trailing garbage makes the whole candidate STOP.
|
||||
|
||||
## Reproducible Corpus
|
||||
|
||||
erofs-utils 1.8.6 twice generates each fixed-time, fixed-UUID, root-owned,
|
||||
xattr-free image from the same 151,552-byte source. Matching fsck extraction
|
||||
reconstructs the complete source. The image hashes are:
|
||||
|
||||
| Codec | Image SHA-256 | Selected real extent | Leading zero padding | Stream |
|
||||
|---|---|---:|---:|---:|
|
||||
| LZMA | `c26cf15844fe45a21a746bacbad2ef551c683bb9b2538de7a7eced37d8eadff9` | 4,096 + 4,096 | 3,556 | 540 |
|
||||
| Deflate | `39455150c3e999bb7ae6c36402c15a408a5679726b6d099e7d121e009ef43af6` | 28,672 + 4,096 | 1,479 | 2,617 |
|
||||
| Zstd | `b905803f0e08500cc3c6cfe07a95fe027859165acae19ca8865856af256f32ca` | 4,096 + 4,096 | 1,092 | 3,004 |
|
||||
|
||||
The leading zero bytes are legal EROFS pcluster padding. They are removed by
|
||||
the common dispatch before the codec callback, matching Linux
|
||||
`z_erofs_fixup_insize()`. Every remaining legal stream reaches the format end,
|
||||
consumes every byte, reproduces the selected logical extent, and leaves its
|
||||
output guards intact.
|
||||
|
||||
## Per-Codec Policy
|
||||
|
||||
- Deflate: a full raw stream must reach `Z_STREAM_END` with no unread input.
|
||||
The independent zlib decoder consumes 2,617 of 2,625 bytes after an 8-byte
|
||||
nonzero tail and reproduces the output. fsck also accepts that mutation, as
|
||||
does the Linux streaming loop when output is already full, but the bytes are
|
||||
not EROFS leading padding and no mkfs fixture emits them. The audited FreeBSD
|
||||
full policy rejects them with positive `EINTEGRITY` (97).
|
||||
- LZMA: MicroLZMA stores no end marker and requires an exact compressed size.
|
||||
The legal 540-byte stream consumes all bytes. Adding the same tail produces
|
||||
liblzma status 9 after consuming 540 of 548 bytes; fsck rejects it and the
|
||||
FreeBSD policy returns 97.
|
||||
- Zstd: exactly one frame must finish with no unread input. The library finds
|
||||
frame end after 3,004 of 3,012 bytes with the tail present; fsck rejects the
|
||||
source-size mismatch and the FreeBSD policy returns 97. A concatenated or
|
||||
skippable second frame is not EROFS pcluster padding.
|
||||
|
||||
This is deliberately codec-specific. It aligns Linux's non-LZ4 leading-padding
|
||||
placement and stream completion semantics without copying the Linux wrappers'
|
||||
implicit unread-byte acceptance into the FreeBSD provider path.
|
||||
|
||||
## Partial, Corruption, and Cleanup
|
||||
|
||||
The independent libraries decode real-stream prefixes that match the full
|
||||
slice: Deflate produces 3,587 bytes after consuming 715, LZMA produces 4,096
|
||||
after consuming 352, and Zstd produces 4,096 after consuming 1,457. Replacing
|
||||
the final 64 stream bytes with zero begins strictly after each partial
|
||||
consumption boundary. The same partial request still succeeds and matches;
|
||||
full decode and fsck both fail for all three codecs, with the audited FreeBSD
|
||||
policy mapping the full failure to 97. Removing the final compressed byte also
|
||||
returns 97 for all three.
|
||||
|
||||
Every library path reports cleanup complete and unchanged guards. Frozen
|
||||
`zdata.c` releases metadata or physical input after the callback, frees failed
|
||||
decoded output, and publishes only successful output. The owned temporary tree
|
||||
was removed. QEMU, protected PID 26318, port 9222, and the shared base image
|
||||
were not touched. The full feature suite was not run.
|
||||
|
||||
## Consequence
|
||||
|
||||
B27 may now make these three existing policies explicit in the exact planned
|
||||
write set and add TC176 host/QEMU coverage. It must preserve positive FreeBSD
|
||||
errno, optional Zstd ABI, provider/GEOM ownership, input release, failed-output
|
||||
free, and successful-output lifetime. The generated images, extracted files,
|
||||
oracle source, and oracle binary remain temporary and are not committed.
|
||||
@@ -0,0 +1,147 @@
|
||||
# P15-086 Stage0 Decision
|
||||
|
||||
Status: `GO`. G04 and G05 authorize B28 partial subextent decoding for LZ4,
|
||||
LZMA, and Deflate. Zstd is not authorized for partial decoding and must use the
|
||||
exact full-decode fallback for ordinary strict subextent reads. Existing
|
||||
partial-reference maps retain their bounded-prefix path. Shifted, interlaced,
|
||||
unknown, and future backends also remain on full fallback unless a new gate
|
||||
authorizes them.
|
||||
|
||||
The gate is bound to DUT BASE
|
||||
`6bf5724619be70f805bbe7d1ba77dd70cdced69f`, FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, erofs-utils generations v1.4,
|
||||
v1.7, and v1.8.6 for LZ4, erofs-utils 1.8.6 for the stream codecs, liblz4
|
||||
1.10.0, liblzma 5.8.1, zlib 1.3.1, and libzstd 1.5.7.
|
||||
|
||||
## Authoritative Run
|
||||
|
||||
The gate ran once from `/work/erofs-freebsd-pre` as:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 repo-pre-15/tests/pre15/gates/P15-086.sh \
|
||||
--base 6bf5724619be70f805bbe7d1ba77dd70cdced69f \
|
||||
--output planning/pre15/evidence/20260815T154915Z-G04-G05-P15-086/gate-output
|
||||
```
|
||||
|
||||
It returned 0 and recorded G04=`GO`, G05=`GO`, and B28=`AUTHORIZED`.
|
||||
Evidence is rooted at
|
||||
`planning/pre15/evidence/20260815T154915Z-G04-G05-P15-086/`. The authoritative
|
||||
script SHA-256 is
|
||||
`591e407f20a6c8ab5d506329b3bd39ff7bd7f78b66ac86b9db2c45a498b31184`, the
|
||||
input SHA-256 is
|
||||
`62f7f505aef846fa85085039b2f47e252e11602e6ef1bf41f56841cdc9089a2a`, and
|
||||
the result SHA-256 is
|
||||
`33ef86b73447cd8c8099dc33901b9c4fff6c8ecedda3837d25cac9463a369d4f`.
|
||||
|
||||
## Decision Rule
|
||||
|
||||
Each codec is decided independently. A codec is partial-capable only when real,
|
||||
twice-reproduced EROFS input decodes every requested range to the exact full
|
||||
slice, reports a consumed-byte boundary before the end of the stream, leaves
|
||||
guard pages unchanged, preserves positive FreeBSD errno, and reduces peak
|
||||
temporary bytes by at least 20 percent without exceeding the fixed hard budget.
|
||||
Failure of the benefit subgate selects exact full fallback for that codec; an
|
||||
incorrect slice, unbounded memory, missing corruption boundary, or missing
|
||||
oracle stops P15-086.
|
||||
|
||||
## Reproducible Corpus
|
||||
|
||||
All images are fixed-time, fixed-UUID, root-owned, and generated twice with
|
||||
identical bytes. Matching fsck reconstructs every legal source.
|
||||
|
||||
| Codec | Generator | Image SHA-256 | Logical bytes | Physical bytes | Leading zero bytes | Stream bytes |
|
||||
|---|---|---|---:|---:|---:|---:|
|
||||
| LZ4 | v1.4 | `8f940673ed9f7e00efc5c0f06d41b2216748ea84256b740751aabff0d632de2b` | 1,038,906 | 4,096 | 0 | 4,096 |
|
||||
| LZ4 | v1.7 | `93451e563f4eaf95b2690381074b5dfb3da0257691043c51619fd7d4c68dba7e` | 1,038,906 | 4,096 | 0 | 4,096 |
|
||||
| LZ4 | v1.8.6 | `853649c78b159161421a6e833e0c516216382f3e8d135fc80aacd509ddb27b2c` | 1,038,906 | 4,096 | 0 | 4,096 |
|
||||
| Deflate | 1.8.6 | `5f98ff39be30b1396be8164e54a8ae80b144d181d5295a640b2e7814406d7a2d` | 22,878 | 4,096 | 1 | 4,095 |
|
||||
| LZMA | 1.8.6 | `887d4a9baf629533c8d512177a84ca256a20135157d29a201408534f63230889` | 151,552 | 4,096 | 3,556 | 540 |
|
||||
| Zstd | 1.8.6 | `93f6beb46e77187ea8b0fc1ad3a5a1cb565d546d9ce40d51278f26d67187d5fa` | 151,552 | 4,096 | 1,092 | 3,004 |
|
||||
|
||||
The LZ4 corpus spans all three historical generators required by G04. Stream
|
||||
codec consumption is reported by independent liblzma, zlib, and libzstd
|
||||
decoders after the common EROFS leading-zero padding is removed. LZ4 is checked
|
||||
by an independent raw parser and liblz4 partial/full output.
|
||||
|
||||
## Hard Budget and Benefit
|
||||
|
||||
The fixed input cap is 1 MiB, the decoded-output cap is 12 MiB, and the caller
|
||||
cap is 1 MiB. Codec workspace caps are 0 for LZ4, 512 KiB for Deflate, 9 MiB
|
||||
for LZMA, and 4 MiB for Zstd. These caps cover the frozen format maxima rather
|
||||
than only the selected 4 KiB pclusters.
|
||||
|
||||
| Codec | Workspace full/partial | Hard cap | Baseline peak | Candidate peak | Reduction | CPU median partial/full | Decision |
|
||||
|---|---:|---:|---:|---:|---:|---:|---|
|
||||
| LZ4 v1.8.6 | 0 / 0 | 14,680,064 | 1,047,098 | 12,288 | 98.826% | 10,688 / 208,150 ns | `GO` |
|
||||
| Deflate | 39,928 / 39,928 | 15,204,352 | 70,998 | 52,216 | 26.454% | 14,207 / 61,627 ns | `GO` |
|
||||
| LZMA | 98,992 / 98,992 | 24,117,248 | 258,736 | 111,280 | 56.991% | 21,384 / 80,329 ns | `GO` |
|
||||
| Zstd | 95,992 / 313,080 | 18,874,368 | 255,736 | 325,368 | -27.228% | 109,253 / 91,015 ns | `FULL_FALLBACK` |
|
||||
|
||||
All three LZ4 generations have the same 98.826 percent memory reduction; their
|
||||
partial/full CPU ratios are 4.845, 4.632, and 5.135 percent. The gate collected
|
||||
nine samples of 25 decodes per mode and stopped at that fixed sample count.
|
||||
CPU timings are diagnostic because host scheduling produced visible outliers;
|
||||
the authorization is based on deterministic peak temporary bytes. No noisy CPU
|
||||
sample is used to rescue a codec that misses the 20 percent memory threshold.
|
||||
|
||||
## Ranges, Corruption, and Errno
|
||||
|
||||
Prefix, cross-page, middle, and tail requests all match the corresponding full
|
||||
slice. The tail request reaches the extent end and therefore exercises full
|
||||
fallback. Prefix consumption is 1,032 bytes for LZ4, 805 for Deflate, 352 for
|
||||
LZMA, and 1,457 for Zstd. Corruption begins later at stream offsets 4,032,
|
||||
4,031, 476, and 2,940 respectively. Every partial prefix remains byte-exact;
|
||||
the same full read and every one-byte truncation return positive `EINTEGRITY`
|
||||
(97). Real corrupted EROFS images fail matching fsck. All output guards and
|
||||
codec cleanup checks pass.
|
||||
|
||||
Partial success is only evidence that the requested slice is correct. It is not
|
||||
reported as verification of bytes after the consumed boundary or of the full
|
||||
extent.
|
||||
|
||||
## State and Cleanup Model
|
||||
|
||||
B28 adds no persistent cache, owner, waiter, pool, or unmount-drain state. A
|
||||
cache hit remains first. A gate-authorized strict subextent miss decodes into a
|
||||
request-local bounded prefix and never publishes a partial cache entry. Full
|
||||
requests, unsupported ordinary strict subextent codecs, shifted/interlaced
|
||||
maps, and arithmetic fallback retain the existing exact full-decode/cache
|
||||
policy. Existing partial-reference maps remain bounded-prefix and
|
||||
cache-ineligible. Failure frees the local output after input release; success
|
||||
publishes no shared partial state. Reclaim, eviction, unmount, and key reuse
|
||||
therefore retain their existing ownership model.
|
||||
|
||||
The owned temporary tree was removed and the evidence SHA-256 manifest verifies
|
||||
in full. No QEMU process was started. Protected PID 26318, port 9222, and the
|
||||
shared base image were not touched. The full feature suite was not run.
|
||||
|
||||
## Consequence
|
||||
|
||||
B28 may implement bounded-prefix decode only for LZ4, LZMA, and Deflate in the
|
||||
exact planned write set for ordinary strict subextent reads. Zstd and all
|
||||
non-authorized backends must retain exact full fallback there without returning
|
||||
an unsupported error; existing partial-reference behavior remains unchanged.
|
||||
B28 acceptance owns D, the targeted TC176 host case, both KLD configurations,
|
||||
and strict-timeout TC176 QEMU. It must preserve guards, consumed-byte semantics,
|
||||
positive errno, cache eligibility, provider/GEOM ownership, and cleanup
|
||||
ordering.
|
||||
|
||||
## B28 Execution Outcome
|
||||
|
||||
B28 source/test commit
|
||||
`7a0d7e4a4047ac6d6130a3be5cb677cb94979fe7` has the exact 11-path actual
|
||||
write set. LZ4, LZMA, and Deflate ordinary strict subextent reads decode a
|
||||
bounded prefix; Zstd and non-authorized backends use exact full fallback.
|
||||
Existing partial-reference maps remain bounded-prefix and cache-ineligible.
|
||||
|
||||
Final D, targeted host TC176 subset
|
||||
`20260815T163642Z-host-B28-partial-1356298-0`, and targeted zstdio0/zstdio1 K2
|
||||
`20260815T163515Z-host-B28-partial-1355895-0` pass. Earlier host and K2
|
||||
`RUNNER_FAIL` records are retained with their corrected oracle/build findings.
|
||||
The strict-timeout QEMU run
|
||||
`20260815T163824Z-qemu-B28-partial-1356729-0` is `INFRA_BLOCKED` because guest
|
||||
SSH did not become ready before the boot deadline; it did not reach the target
|
||||
marker, so no guest TC176 runtime PASS is claimed. Owned cleanup passes,
|
||||
protected PID 26318 and port 9222 were untouched, and the full feature suite was
|
||||
not run. Complete evidence is under
|
||||
`planning/pre15/evidence/20260815T161336Z-B28/`.
|
||||
@@ -0,0 +1,95 @@
|
||||
# P15-087 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B12 is `STOP-NO-SOURCE`; no production source, B12 case, or
|
||||
B12 fixture is authorized.
|
||||
|
||||
The final decision uses frozen DUT BASE
|
||||
`c7d692acf9166f5c5e42335db2de64f0793ba8a2`, FreeBSD source HEAD
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, and
|
||||
`mkfs.erofs (erofs-utils) 1.8.6`. The final gate script and input SHA256 values
|
||||
are `349720b900ad2288153c9830f5f5ee84b8da707c06ffabcbd8e3e7a7e89f9e2a`
|
||||
and `cb3aaa6c780c7b1efbd7c339f2b2da2ed8bf38d3ba32229dc17996807fd00787`.
|
||||
|
||||
## Workload and Independent Oracle
|
||||
|
||||
The gate deterministically creates 18,000 long-name regular files. Since
|
||||
erofs-utils tailpacks the root directory even with `-E noinline_data`, the
|
||||
generator moves the final 1,456-byte tail into one appended contiguous block,
|
||||
changes only the root layout from flat-inline to flat-plain, increments the
|
||||
superblock block count, and recomputes CRC32C. A second generation is
|
||||
byte-identical and `fsck.erofs -d0` exits zero.
|
||||
|
||||
The independent parser does not call DUT code. It verifies a 3,880,368-byte
|
||||
flat-plain directory at physical block 282, covering 948 contiguous 4 KiB
|
||||
blocks and 18,002 entries. Its expected final cookie is 3,880,368 and its
|
||||
record FNV64 is `427bb414efa99dc0`; the random offset is 1,937,408. The fixture
|
||||
SHA256 is `3ecc5b706dd43b734c7e14a648a2bed2fb97a9f7963d4db703d15de81dc07a9d`.
|
||||
The immutable `oracle.json` SHA256 is
|
||||
`f247bbe5029301265342ff2098fcbd463a25e4752608826cbc1126d6620ef5d6`.
|
||||
|
||||
The generated prototype patch SHA256 is
|
||||
`33b25131a611eec9c8731e88e4c258dfc92fe5897dd6781b6c95414a846dd2d1`.
|
||||
Static extraction proves that it calls `breadn` only on the mapped backing
|
||||
`devvp`, does not call `breadn` on the EROFS directory vnode, caps the window
|
||||
at exactly 1 MiB, gates readahead on an offset-zero sequential readdir, and
|
||||
adds no VM entrypoint, vnode lock, GEOM ownership operation, `cluster_read`,
|
||||
or errno token. The `semantic-ledger.json` SHA256 is
|
||||
`d26dbc37f4f34f65d07745a1b8069217d18545436d7f16f24e775e8c2db1a6b3`.
|
||||
This closes the static design boundary but cannot replace runtime proof.
|
||||
|
||||
## Quantitative Decision
|
||||
|
||||
| Required G11 measurement | Required | Valid result | Decision |
|
||||
|---|---:|---:|---|
|
||||
| Cold sequential runs | 5 baseline + 5 prototype | 0 + 0 | FAIL: no median |
|
||||
| Median latency improvement | at least 10% | not measurable | FAIL |
|
||||
| Extra provider reads | at most 25% | not measurable | FAIL |
|
||||
| Readahead window | at most 1 MiB | 1 MiB static cap | PASS |
|
||||
| Random seek readahead | zero | 0 valid runtime samples | FAIL: not verified |
|
||||
| Hash/cookie equality | exact independent oracle | 0 valid runtime samples | FAIL: not verified |
|
||||
|
||||
No run produced `runs.tsv`; therefore no latency, read-transfer, random-no-op,
|
||||
or runtime hash/cookie value is claimed. It would be dishonest to infer GO
|
||||
from the static prototype, from QEMU startup, or from build progress. Because
|
||||
the workload could not be measured credibly and repeatably, G11's explicit
|
||||
rule requires low-confidence STOP even though the 1 MiB static bound passes.
|
||||
|
||||
## Replay Ledger
|
||||
|
||||
The authoritative command shape was:
|
||||
|
||||
```sh
|
||||
timeout -k 30 1200 tests/pre15/gates/P15-087.sh \
|
||||
--base c7d692acf9166f5c5e42335db2de64f0793ba8a2 \
|
||||
--output OWNED_OUTPUT
|
||||
```
|
||||
|
||||
Existing evidence was retained long enough to hash and reconcile before
|
||||
repository cleanup:
|
||||
|
||||
| Run ID | Result before any benchmark sample |
|
||||
|---|---|
|
||||
| `20260815T044720Z-G11-P15-087` | Superseded generator STOP: mkfs root remained flat-inline |
|
||||
| `20260815T044924Z-G11-P15-087` | `INFRA_BLOCKED`: 12 boot-time providers exceeded SSH deadline |
|
||||
| `20260815T045505Z-G11-P15-087` | `INFRA_BLOCKED`: FreeBSD did not enumerate PCI-hotplugged virtio-blk devices |
|
||||
| `20260815T050003Z-G11-P15-087` | `INFRA_BLOCKED`: guest benchmark declaration error |
|
||||
| `20260815T050520Z-G11-P15-087` | `INFRA_BLOCKED`: baseline KLD load did not reach workload |
|
||||
| `20260815T051933Z-G11-P15-087` | `INFRA_BLOCKED`: phased baseline KLD load did not reach workload |
|
||||
| `20260815T053543Z-G11-P15-087` | `INFRA_BLOCKED`: exact-basename baseline KLD load did not reach workload |
|
||||
| `20260815T054540Z-G11-P15-087` | Aborted on instruction; owned process group terminated and audited |
|
||||
|
||||
Each completed QEMU ownership record reports that the owned port was free
|
||||
after cleanup, protected PID 26318 retained the same identity, protected port
|
||||
9222 was not used, and `/work/build/vm-freebsd-build.qcow2.bp` retained inode,
|
||||
size, mtime, and ctime. The interrupted run used owned PID 1172175 and port
|
||||
49845; both were absent after targeted process-group cleanup. Final process
|
||||
audit found only protected QEMU PID 26318.
|
||||
|
||||
## Semantic and Batch Consequences
|
||||
|
||||
Runtime preservation of FreeBSD vnode, VM, locking, GEOM, errno, hash, and
|
||||
cookie behavior was not established. Correctness may not depend on
|
||||
readahead, so static plausibility is insufficient. P15-087 is STOP for Pre15,
|
||||
B12 remains absent, and no host feature case, K0 build, TC183 QEMU acceptance,
|
||||
or full feature suite is run. Rollback is the single gate decision commit;
|
||||
there is no source commit to revert.
|
||||
@@ -0,0 +1,142 @@
|
||||
# P15-092 Stage0 Decision
|
||||
|
||||
Status: `STOP`. B15 is `STOP-NO-SOURCE`; terminal static review status is
|
||||
`TERMINAL_REVIEWED_NO_SOURCE`. No production source, B15 case, or B15 fixture
|
||||
was created. Historical acceptance remains `NOT_TESTED`.
|
||||
|
||||
P15-092 is the G11 zero-nlink candidate. The frozen BASE is
|
||||
`b22dae8dc634c68db4ea89dccade91350614c139`, the FreeBSD source HEAD is
|
||||
`106727738dcfb6c001b46f25363b91cece970085`, the erofs-utils source HEAD is
|
||||
`7db78788b000999e2de88decd2ba90654f26171c`, and the generator is
|
||||
`mkfs.erofs (erofs-utils) 1.8.6`. Linux EROFS identity is frozen by the three
|
||||
source hashes in `P15-092-input.json` and the Pre15 semantic audit hash ledger.
|
||||
|
||||
The final gate script and input SHA256 values are
|
||||
`5943b85864da9095174ef51d1eed032ec6f0a1766c6465cb9660ea20cbd46b1e`
|
||||
and `0a6f6c76185644d3f5525a98429a310027556ef3cf7ebb43abb912f92e052bde`.
|
||||
|
||||
## Real Disk Oracle
|
||||
|
||||
The gate creates the same deterministic source tree twice in forced compact
|
||||
form and twice in forced extended form. It uses fixed UUID, timestamp, worker
|
||||
count, xattr policy, and inline-data policy. Both complete host output trees
|
||||
are byte-identical.
|
||||
|
||||
An independent parser reads the real superblock, checksum span, metadata block,
|
||||
root NID, directory entries, compact `i_nb.nlink`, extended `i_nlink`, and the
|
||||
compact `EROFS_I_NLINK_1_BIT` rule. It then materializes seven images:
|
||||
|
||||
- compact and extended positive seeds;
|
||||
- namespace-reachable compact, extended, and directory inodes with nlink zero;
|
||||
- a root inode with nlink zero;
|
||||
- an unreachable inode with nlink zero, whose former name is redirected to a
|
||||
real hardlink NID and whose replacement link count is corrected to three.
|
||||
|
||||
Every derived image has a recomputed valid EROFS CRC32C. `dump.erofs --path`
|
||||
resolves the actual directory edge and NID; no DUT helper or internal value
|
||||
injection is used. All seven images, including all three namespace-reachable
|
||||
zero-nlink images, pass `fsck.erofs -d0` with no error marker. The fixture-set
|
||||
SHA256 is `99897d4fd81da015bdaa66a5dfdbf3f42e9e830882c0d8c979e691fa9209ee7a`.
|
||||
|
||||
Key deterministic host evidence SHA256 values are:
|
||||
|
||||
- `host-result.json`: `59a27e9389e2771c921d689f6b76caeb858f0fd28487a933529153727aac12e8`
|
||||
- `disk-records.json`: `44bf0355dc5b34e93ec6868db9f9049de32500591b048a9016bf46aed9609485`
|
||||
- `boundary.json`: `985df1236c6dd2016d6cb244b71578d36bd4cd10aa273b60a92d5bb6d24d5b60`
|
||||
- `format-semantics.json`: `88efc1d7814103c044b36ff4dc3cac1dfa4da79f3d8955c682d1a60d9bfd9fcf`
|
||||
- `fixture-index.json`: `4d2b69bcc31709ecb96cfafb41f5db8ffcc97215c3290cfa476d0b6c7fc27886`
|
||||
- `source-anchors.json`: `ef9e6871d5fe1a3a6113f1172340269da4ea0c1692003aad0b0fee06ec4deb42`
|
||||
|
||||
## Linux and FreeBSD Semantics
|
||||
|
||||
Linux EROFS calls `set_nlink()` with the compact or extended disk value and has
|
||||
no zero-nlink rejection in inode decode or super initialization. This is an
|
||||
inode/link-count behavior, not a FreeBSD vnode publication rule. Linux and
|
||||
FreeBSD both permit a live unlinked inode/vnode with link count zero; the
|
||||
FreeBSD VM code explicitly treats `va_nlink == 0` as an unlinked mapping case.
|
||||
|
||||
The FreeBSD EROFS adapter has three distinct entry semantics:
|
||||
|
||||
1. `erofs_lookup()` owns a non-dot namespace edge and calls `erofs_vget()`.
|
||||
2. `.vfs_vget = erofs_vget` is the raw NID entry used by VFS/root callers.
|
||||
3. `erofs_fhtovp()` calls raw `VFS_VGET` and then maps `nlink == 0` to `ESTALE`.
|
||||
|
||||
Therefore Linux's direct `set_nlink()` behavior does not authorize either a
|
||||
global FreeBSD rejection or a namespace-only rejection. The latter would be a
|
||||
new FreeBSD validator policy, and the disk/fsck corpus supplies no format-level
|
||||
rule requiring it.
|
||||
|
||||
## Publication Boundary
|
||||
|
||||
B09 moved the vnode constructor to `src/erofs_vnops.c`, but the frozen B15
|
||||
write set is only `src/namei.c` and `src/inode.c`. `erofs_vget()` inserts the
|
||||
constructing vnode in the hash, decodes the inode, marks it
|
||||
`VSTATE_CONSTRUCTED`, and only then returns to `erofs_lookup()`.
|
||||
|
||||
A post-`erofs_vget()` check in `namei.c` is therefore too late to reject before
|
||||
vnode publication. `vput()` alone does not perform the required `vgone`
|
||||
cleanup. An unconditional `vgone()` cannot preserve an already cached vnode
|
||||
obtained through raw `VFS_VGET`, because `erofs_vget()` does not return a
|
||||
created-versus-hit indicator. Pre-reading through `erofs_read_inode()` would
|
||||
duplicate complete inode decode and metadata I/O on every cold namespace
|
||||
lookup, then decode the same inode again in `erofs_vget()`.
|
||||
|
||||
The four failed GO requirements are consequently:
|
||||
|
||||
- no format or cross-kernel rule requires reachable zero-nlink rejection;
|
||||
- rejection before vnode publication is unavailable within the exact B15
|
||||
write set;
|
||||
- post-publication cleanup cannot preserve cached raw VGET semantics;
|
||||
- pre-reading would duplicate full inode decode for a low-value validator.
|
||||
|
||||
Namespace and raw entrypoints are distinguishable, and the orphan needs no
|
||||
mount-wide scan, but those two facts do not outweigh the failed safety,
|
||||
compatibility, and cost requirements. P15-092 is therefore STOP rather than a
|
||||
partial or expanded-write-set implementation.
|
||||
|
||||
## Replay and Infrastructure
|
||||
|
||||
The authoritative deterministic host command was run twice:
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 tests/pre15/gates/P15-092.sh \
|
||||
--base b22dae8dc634c68db4ea89dccade91350614c139 \
|
||||
--output OWNED_OUTPUT --host-only
|
||||
```
|
||||
|
||||
Both runs exit `22` with `STOP` and have byte-identical host output trees.
|
||||
|
||||
One supplemental isolated runtime attempt used the standalone
|
||||
`/work/debug-qemu/local/vm/freebsd-build-runtime.qcow2`, not the protected base
|
||||
bp, with a fresh overlay, random port, exact baseline KLD, 180-second boot
|
||||
deadline, 60-second guest command deadlines, 900-second inner timeout, and
|
||||
1200-second outer timeout. Run
|
||||
`20260815T083854Z-qemu-P15-092-gate-runtime-1219662-0` was
|
||||
`INFRA_BLOCKED`: guest SSH did not become ready before the boot deadline, so no
|
||||
runtime vnode result is claimed. The run used only PID `1219981` and port
|
||||
`49795`; it did not own PID `26318`, port `9222`, or the protected base bp.
|
||||
|
||||
Cleanup is `PASS`: the owned QEMU PID stopped, port `49795` is free, the
|
||||
overlay and case temp were removed, and the standalone base SHA256 remained
|
||||
`ae09f47aef43cfd016049610e86bcf2073fdf70430961bcdb94662facac9f046`.
|
||||
The runtime manifest and cleanup SHA256 values are
|
||||
`2e9a4220dc86c5d8fa465e77e6d81e5e36c0f26338b70d71a84881af8fc02cb9`
|
||||
and `0a499d8fa3397f73998c6c3c3ae9dfc9070f61267a86361ba96d1e8bc64cb392`.
|
||||
|
||||
Because the reproducible host gate already fails mandatory GO conditions, the
|
||||
runtime infrastructure block does not defer or weaken the STOP decision. It is
|
||||
reported separately and was not retried with another long-running VM. B15,
|
||||
TC021, TC025, TC182, K0, and B15 acceptance QEMU are `NOT_RUN` by the mandatory
|
||||
STOP-NO-SOURCE rule. The full feature suite was not run.
|
||||
|
||||
## Terminal Static Review
|
||||
|
||||
The 2026-08-17 review rechecked the current `repo-pre-15`, Linux EROFS
|
||||
implementation, P15-092 plan, frozen write set, and post-STOP history. It
|
||||
found no format or cross-kernel requirement for namespace zero-nlink
|
||||
rejection, no new B15 consumer or test target, and no safe implementation
|
||||
entry within the frozen write set. The detailed evidence is
|
||||
`planning/pre15/evidence/20260817T-B15-terminal-review/VERDICT.md`.
|
||||
|
||||
The terminal review does not convert the historical STOP or acceptance state:
|
||||
`STOP_NO_SOURCE` and `NOT_TESTED` remain the authoritative historical values.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Pre15 Stage0 Execution Evidence
|
||||
|
||||
## Scope
|
||||
|
||||
B01 establishes the only Pre15 runner interface and the evidence contract used
|
||||
by later gates, builds, directed tests, and smoke runs. It does not modify
|
||||
`src/**`, run the full feature suite, or convert host parser results into KLD
|
||||
runtime claims.
|
||||
|
||||
## Entrypoints
|
||||
|
||||
```sh
|
||||
timeout -k 10 240 tests/pre15/run-host.sh CASE
|
||||
timeout -k 30 1200 tests/pre15/run-build.sh zstdio0
|
||||
timeout -k 30 1200 tests/pre15/run-build.sh zstdio1
|
||||
timeout -k 30 1200 tests/pre15/run-qemu.sh CASE
|
||||
timeout -k 30 1500 tests/pre15/run-smoke.sh final-four-codec
|
||||
```
|
||||
|
||||
Cases are discovered as exact files under `tests/pre15/cases/`; no shared case
|
||||
registry or historical result runner is consulted. `run-build.sh` reports a
|
||||
Linux invocation as `INFRA_BLOCKED` because `build.sh` requires a native
|
||||
FreeBSD host.
|
||||
|
||||
## Evidence
|
||||
|
||||
Set `PRE15_EVIDENCE_ROOT` to a new evidence parent. Every invocation creates a
|
||||
unique run directory and never overwrites an earlier run. `manifest.json`
|
||||
conforms to `tests/pre15/EVIDENCE-SCHEMA.json` and records exact argv, DUT and
|
||||
source identities, worktree diff hash, fixture/module hashes, timestamps,
|
||||
deadline, exit code, target marker, status, cleanup, and raw-output paths.
|
||||
|
||||
The only case statuses are `PASS`, `DUT_FAIL`, `RUNNER_FAIL`,
|
||||
`INFRA_BLOCKED`, `STOP`, and `NOT_RUN`. A nonzero guest command without a target
|
||||
marker is not a DUT failure. Cleanup failure always changes the run to
|
||||
`RUNNER_FAIL`.
|
||||
|
||||
## Ownership
|
||||
|
||||
The runner records each owned process, path, forwarded port, SSH ControlMaster,
|
||||
guest mount, md unit, loaded EROFS KLD, and base image before use. Cleanup runs
|
||||
in reverse order and refuses to remove paths outside the current run directory.
|
||||
QEMU always writes to a fresh overlay. The base image is read-only input for the
|
||||
runner and its SHA256 must remain unchanged.
|
||||
|
||||
Mount, md, and KLD cleanup applies only to resources explicitly registered by
|
||||
the current run. Kernel ZSTDIO is a kernel option, not an unloadable dependency.
|
||||
|
||||
## B01 Controls
|
||||
|
||||
- `B01-runner-selftest`: known-good, target-marked DUT mismatch, pre-target
|
||||
command failure, SSH failure, QEMU early exit, timeout, owned PID cleanup, and
|
||||
deliberate cleanup-boundary failure.
|
||||
- `B01-g3-equivalence`: verifies the two archived script identities, compares
|
||||
their source/artifact inventories with the stable helper, and repeats stable
|
||||
generation.
|
||||
- `TC162-xattr-legacy`: verifies checksum-valid legacy primary, explicit plain,
|
||||
packed, and metabox prefix carriers plus exact single-field `EINTEGRITY`
|
||||
negatives.
|
||||
|
||||
The authoritative B01 and initial gate verdicts are recorded under
|
||||
`planning/pre15/evidence/` after execution from a committed B01 tree.
|
||||
@@ -0,0 +1,101 @@
|
||||
# Phase 0: B-ZSTD-001 Remediation
|
||||
|
||||
Status: `FIXED_STATICALLY`; runtime corruption-tail verification remains
|
||||
`NOT_TESTED` in this remediation pass.
|
||||
|
||||
## Problem
|
||||
|
||||
Strict audit item B-ZSTD-001 / BUG-ZSTD-035 found that ordinary ZSTD extents
|
||||
advertised subextent support. A prefix or middle read could therefore decode
|
||||
only the requested output and accept `z_erofs_zstd_finish()` without checking
|
||||
the remaining compressed stream. Corruption after the requested range could be
|
||||
skipped.
|
||||
|
||||
P15-086 already authorizes partial ordinary reads only for LZ4, LZMA, and
|
||||
Deflate. Its ZSTD result is `FULL_FALLBACK` because the partial candidate used
|
||||
more temporary memory than full decode.
|
||||
|
||||
## Call Graph
|
||||
|
||||
For an ordinary mapped compressed read:
|
||||
|
||||
1. `z_erofs_do_read()` calls `z_erofs_decode_length()` with `mapoff` and
|
||||
`want`.
|
||||
2. `z_erofs_decode_length()` sets `partial=true` and `decoded_len=mapoff+want`
|
||||
when the descriptor reports `supports_subextent` and the request ends before
|
||||
the extent.
|
||||
3. `z_erofs_decode_extent()` passes that length and mode to
|
||||
`z_erofs_decompress()`.
|
||||
4. `z_erofs_zstd_decompress()` fills the shortened output and calls
|
||||
`z_erofs_zstd_finish()`.
|
||||
5. `z_erofs_zstd_finish()` intentionally permits partial decoding without
|
||||
requiring stream end. That behavior remains necessary for the separately
|
||||
defined `EROFS_MAP_PARTIAL_REF` bounded-prefix path.
|
||||
|
||||
The smallest correct policy fix is to stop ordinary ZSTD reads at step 2:
|
||||
ZSTD now advertises `.supports_subextent = 0`. `z_erofs_decode_length()` then
|
||||
selects the full extent for ordinary prefix and middle reads. The explicit
|
||||
`EROFS_MAP_PARTIAL_REF` branch still sets `partial=true` and remains unchanged.
|
||||
|
||||
## Changes
|
||||
|
||||
- Set the ZSTD descriptor capability to false in
|
||||
`src/decompressor_zstd.c`; no finish validation was weakened or bypassed.
|
||||
- Updated B27 assertions to preserve ZSTD partial-reference completion while
|
||||
requiring ordinary ZSTD full fallback.
|
||||
- Updated B28 source and extracted-policy assertions, host report, and QEMU
|
||||
corruption decision so ZSTD is `FULL_FALLBACK`; LZ4/LZMA/Deflate policy is
|
||||
unchanged.
|
||||
|
||||
## Verification
|
||||
|
||||
Commands and actual results:
|
||||
|
||||
- `git diff --check`: `PASS`.
|
||||
- `sh -n repo-pre-15/tests/pre15/cases/B27-stream-tail.sh` and
|
||||
`sh -n repo-pre-15/tests/pre15/cases/B28-partial.sh`: `PASS`.
|
||||
- `PRE15_EVIDENCE_ROOT=/tmp/erofs-phase0-b28-20260818-r2 timeout -k 10 600
|
||||
repo-pre-15/tests/pre15/run-host.sh B28-partial`: `PASS`; cleanup `PASS`,
|
||||
target reached. Evidence:
|
||||
`/tmp/erofs-phase0-b28-20260818-r2/20260818T070848Z-host-B28-partial-1780769-0/`.
|
||||
The source audit reports `zstd=false`, ZSTD in `current_full_fallback`,
|
||||
`current_partial=[deflate,lz4,lzma]`, and partial-reference preserved.
|
||||
- `PRE15_EVIDENCE_ROOT=/tmp/erofs-phase0-b27-20260818 timeout -k 10 600
|
||||
repo-pre-15/tests/pre15/run-host.sh B27-stream-tail`: `RUNNER_FAIL`, cleanup
|
||||
`PASS`; the pre-existing B29 Deflate context-pool delta fails B27's frozen
|
||||
exact-transform audit before the completion harness. This is not claimed as
|
||||
ZSTD runtime evidence.
|
||||
- P15-086 frozen gate result and policy were inspected, not rerun; its existing
|
||||
recorded decision remains ZSTD `FULL_FALLBACK`.
|
||||
|
||||
The B28 host case generated and compared real EROFS fixtures and ran the
|
||||
descriptor/decode-length source audit, but did not load a FreeBSD KLD or read
|
||||
an image through the kernel. No full feature suite was run.
|
||||
|
||||
## Not Tested
|
||||
|
||||
`NOT_TESTED`: a real FreeBSD runtime read of an EROFS ZSTD image whose stream
|
||||
is corrupted after an ordinary prefix or middle request. The required runtime
|
||||
threshold is that the short ordinary read returns positive `EINTEGRITY` (97),
|
||||
matching full fallback, while a valid ordinary prefix/middle/tail read matches
|
||||
the source bytes.
|
||||
|
||||
`NOT_TESTED`: runtime confirmation that `EROFS_MAP_PARTIAL_REF` retains its
|
||||
bounded-prefix semantics on a real image after this policy change.
|
||||
|
||||
## Risk
|
||||
|
||||
Ordinary ZSTD prefix and middle reads now decode the complete extent. This may
|
||||
increase CPU or temporary output work relative to the previously incorrect
|
||||
partial path, but it restores corruption visibility and matches P15-086 policy.
|
||||
The changed tests do not alter test fixtures, image bytes, test environment, or
|
||||
finish-error behavior.
|
||||
|
||||
## Runtime Gate
|
||||
|
||||
Before claiming Phase 0 runtime closure, run the existing focused B28 runtime
|
||||
case with ZSTD enabled and verify valid prefix, middle, and tail reads, an
|
||||
after-request-range corruption case returning `EINTEGRITY`, full corruption
|
||||
returning `EINTEGRITY`, and the real partial-reference case. Record separate
|
||||
`PASS`, `INFRA_BLOCKED`, or `NOT_TESTED` results; do not infer runtime behavior
|
||||
from the extracted C harness.
|
||||
@@ -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