实习总结报告:为块设备存储链路实现异步 I/O 运行时——异步提交、单请求完成与背压机制的设计与实板验证
实习项目:StarryOS 块设备存储链路的异步化改造——为块设备运行时实现异步提交、单请求完成等待与背压机制,在星光 2(VisionFive 2,JH7110)平台 SD 卡上完成实测验证
工作仓库:rcore-os/tgoskits(上游开源仓库),本人仓库:https://github.com/xianxw/tgoskits
一、整体工作概述
1.1 本次改造具体做了什么
实习任务始于星光 2 平台的 SD 卡存储方向:原计划在完成 SD 卡驱动支持的基础上,直接对 SD 卡驱动做异步化改造。完成板卡引导、驱动对接并通过实践验证后,发现直接在驱动层做异步化收益有限——异步的价值在于请求提交与完成等待期间释放执行流,而这需要建立在统一管理请求准入、队列调度与完成路径的块设备运行时层之上,驱动层的单点改造无法获得这些机制。确认后,工作重心调整为块设备运行时的异步化改造,全部工作以 6 个经评审合并的上游 Pull Request 交付。
改造前,任务向块设备提交一次读写请求后,必须同步阻塞在原地等待硬件完成,I/O 期间整个任务无法让出 CPU。改造后,块设备运行时具备了完整的异步 I/O 能力,具体完成了以下五件事:
- 异步提交与完成等待:任务提交读写请求后立即返回并挂起让出 CPU,请求完成时由运行时唤醒等待它的任务;一个请求只唤醒等它的那个任务,不产生假唤醒、不丢唤醒;
- 异步准入与背压:提交队列满载时,任务挂起排队而非空转重试,队列腾出位置后自动恢复提交;
- 并发与取消安全:任务被调度器迁到其他 CPU 恢复后,请求仍提交到原队列;任务中途取消等待时,已进入硬件执行的请求不会被取消,DMA 缓冲由完成路径安全释放,杜绝”取消导致缓冲被过早回收”这类内存错误;
- 异步化的前置地基:先用两个 PR 治理运行时生命周期——Ready 资源唯一发布、设备与队列信息冻结、事务化更新与回滚、终止路径资源隔离——使异步提交建立在状态一致、并发安全的运行时之上;
- 成体系的验证:58 项宿主机确定性单元测试;星光 2 实板 212 项功能回归(
AXTEST_SUITE_OK零失败);riscv64、x86_64、aarch64、loongarch64 四架构 QEMU 全套;实板同步/异步对照基准——32 请求下时延 −27%、吞吐 +36%、上下文切换 −30%。
需要说明,这次改造的不是”SD 卡专用链路”,而是设备无关的块设备运行时:运行时与驱动之间是通用块设备接口,异步路径中没有任何 SD 或星光 2 专属代码。QEMU 测试环境的块设备正是 NVMe,异步读用例在四架构 QEMU 全套中于 NVMe 上真实执行并全部通过;星光 2 SD 卡是功能与性能实测的主要载体。
1.2 本工作在操作系统异步化中的位置
操作系统的异步化是一项分层工程。以一次文件读写从用户态到达 SD 卡的完整路径为参照,各层的异步化职责自下而上依次为:
1 | 用户态接口层 ← 尚未涉及(Linux 侧对应当 io_uring 类接口) |
本实习完成了其中块设备运行时层的异步化,以及它下面的驱动与引导层的基础支撑;运行时之上的文件系统层、系统调用层目前仍以同步方式调用运行时(边界说明见第三节末尾)。
1.3 对后续完整操作系统异步化的帮助
虽然异步链路尚未贯通到用户态,但本工作为后续”整栈异步化”打下了四个方面的直接基础:
- 可复用的异步原语与语义:单请求完成等待、异步准入与背压、安全的取消语义、跨核提交语义。文件系统层将来接异步时,不需要重新设计这些机制,直接复用即可;
- 异步安全性的生命周期前提已经固化:唯一发布者、Ready 信息冻结、事务化更新与回滚、DMA 资源隔离——异步提交/等待若建立在状态可漂移的运行时上会产生难以排查的错误,这些保证现在已有确定性回归测试固化,对上层异步化同样成立;
- 测量方法与回归资产就位:同步/异步同负载的实板对照方法、逐操作延迟分位数与调度指标输出、212 项实板功能回归套件。异步链路每向上贯通一层(ext4 → VFS → 系统调用),都可以用同一套方法量化该层带来的收益,形成”改造一层、验证一层”的递进;
- 硬件收益形态的明确:实测证实单在途控制器上异步收益来自”任务不阻塞在完成等待 + 上下文切换减少”,而非并发带宽。这为上层异步化的投入方向(减少阻塞点而非追求队列深度)提供了依据。
二、远程仓库与分支说明
本人远程仓库:https://github.com/xianxw/tgoskits (上游 rcore-os/tgoskits 的 fork,全部工作分支保存在此)。
| 分支 | 作用 |
|---|---|
| fix/visionfive2-boot | PR #1954:星光 2 引导修复(booti 镜像头、SD 根文件系统挂载) |
| fix/async | PR #2135:块运行时 Ready/SMP 发布过程稳定化 |
| fix/block-runtime-lifecycle | PR #2256:块运行时生命周期线性化 |
| fix/block-runtime-async-latest-20260909 | PR #2349:异步块请求运行时(核心工作) |
| fix/block-runtime-async-test-20260918 | PR #2451:实板同步/异步基准与验证 |
| test/block-runtime-async-performance-20260922 | PR #2515:功能回归固化与破坏性写入安全边界 |
| archive/block-runtime-full-tests | 完整性能测试的独立归档分支 |
归档分支单独说明:按照评审确立的原则,性能测量应当与内核功能回归分离,不应放在生产内核的测试路径里。该分支保存的是分离之前构建在内核测试中的完整性能测试版本,含 5 个块设备性能基准(多块写读对照、混合读写对照、单块读同步/异步对照、I/O 等待与计算重叠、请求尺寸扫描)及配套的延迟汇总、速率输出、CPU 占用统计机制。它仅作历史保存与参考:将来设计独立入口的请求级基准时,负载构造与测量方法可从该分支取材,但不应直接合回内核测试。第四节所述的完整性能测试即来自该分支的实板运行。
三、具体工作一览
全部工作按”先打地基、再实现异步、后固化验证”的顺序分五个阶段推进,以 6 个经评审合并的上游 PR 交付:
| 阶段 | PR | 工作内容 | 交付与验证 |
|---|---|---|---|
| 一:板卡引导与 SD 存储支持 | #1954 | 修复 RISC-V 镜像头错位(booti 报 Bad magic)与 MMC 时钟供给断裂(时钟提供者未对接驱动探测) |
星光 2 实现”SD 卡引导 + 根文件系统挂载”的可重复实板环境 |
| 二:块运行时生命周期治理 | #2135、#2256 | Ready 资源唯一发布;设备与队列信息冻结;生命周期门控状态统一;更新事务化(安装—提交—回滚);终止时资源隔离而非强行释放 | 红-绿确定性回归:rdif-block 28 项、ax-fs-ng 81 项单元 + 3 项集成、nvme-driver 16 项宿主机测试及生命周期交错回归 |
| 三:异步块请求运行时(核心工作) | #2349 | 异步提交与单请求完成等待(不丢醒、不假唤醒);异步准入与背压;跨核提交语义;唤醒/回调/析构移出运行时锁外;取消与 DMA 所有权解耦 | 58 项宿主机确定性单元测试 + StarryOS 异步读 axtest;同步 API 行为不变,同步/异步双路径共存 |
| 四:实板基准与验证 | #2451 | 新增同步对照路径,同一负载(32 个单块请求)下同步/异步实板对照测量 | 时延 −27%、吞吐 +36%、上下文切换 −30%;axtest 198/198 |
| 五:功能回归固化与破坏性写入安全边界 | #2515 | 内核测试收敛为 6 项纯功能回归(清单见 5.1 节);破坏性写入保护区模型(已识别分区、分区表元数据、整盘文件系统)与”先恢复、后报告”恢复流程硬化;性能测量移出内核测试路径 | scratch 资格策略 13 项 + 声明解析 3 项宿主机测试;axtest 212/212,写入区域逐字节恢复校验 |
当前边界需要说明:异步链路止步于块设备运行时层,文件系统层与系统调用层仍以同步方式调用运行时;文件系统接入只需将现有同步调用点替换为异步提交与完成等待,运行时侧原语已全部交付并有测试固化。
四、完整性能测试结果
除正文引用的 32 请求对照基准(时延 −27%、吞吐 +36%、上下文切换 −30%)外,完整性能测试在归档分支上于星光 2 实板运行,包括单块读同步/异步对照与并发深度扫描、多块写读对照、混合读写对照、I/O 等待与计算重叠、请求尺寸扫描共 5 项基准,以及逐操作延迟分位数、每秒速率与 CPU 占用统计和全部运行日志。主要结论有三:异步收益随并发深度单调上升(并发 8 时相对同步 +23.9%);全部运行期间控制器单在途(peak_inflight_global=1),收益来自任务侧重叠而非硬件并发;请求合并(多块)是最大的性能杠杆(吞吐提升约 3.9 倍)。
完整测试数据与运行日志收录在实习日志中,不在本报告完整展开,详见:实习日志·总结报告
五、功能正确性验证
功能正确性验证贯穿全部阶段,按层级与时间线完整记录如下。
5.1 内核功能回归用例(星光 2 实板执行,6 项)
| 用例 | 验证内容 |
|---|---|
| block_runtime_registration_and_read_consistency | 设备注册就绪(容量与逻辑块大小非零);同一 LBA 的同步读与异步读结果逐字节一致;提交/完成/失败计数闭环 |
| block_runtime_async_double_read | 同一任务内并发提交两个异步读;两个请求独立完成、独立唤醒;DMA 缓冲与所有权相互独立(改写其一不影响另一) |
| block_runtime_single_block_contiguous_read_write | 8 次单块同步写 + 逐块异步读回,按确定性 pattern 逐字节校验,测试后区域恢复并校验 |
| block_runtime_multi_block_contiguous_read_write | 真正的多块请求(8 块)走异步写 + 异步读完成路径,完整缓冲内容与块边界校验 |
| block_runtime_multi_descriptor_contiguous_read_write | 16 块(8 KiB)请求跨两个 IDMAC 描述符链式传输(星光 2 DMA 分配 4 KiB 对齐、单描述符上限 4 KiB),覆盖真实链式传输 |
| block_runtime_async_mixed_read_write | 偶数块异步写新 pattern、奇数块异步读原始数据,完成顺序无关,每个请求独立判定 |
每个破坏性用例在测试前后对 scratch 区域做原始字节保存与逐字节恢复校验,保证 SD 卡可复用、不留残留。
5.2 安全门与跳过语义
无 scratch 环境(普通 QEMU)下写用例自动跳过(输出 BLOCK_WRITE_TESTS_SKIPPED)并以成功状态退出,读用例正常执行——保证跨环境 CI 全绿不因环境差异假失败,也不因缺少设备而假通过;安全门本身的资格策略由 13 项宿主机单元测试固化(见 5.5 节)。
5.3 实板运行记录(全部 AXTEST_SUITE_OK、零失败)
| 阶段 | 运行内容 | 结果 |
|---|---|---|
| PR #2451 | 基准 + 功能套件 | 198/198 |
| PR #2515 功能版 | 纯功能回归(性能移出后) | 205/205 |
| 归档分支完整版 | 完整性能测试套件 + 功能回归 | 210/210 |
| PR #2515 最终版 | 功能回归 + 安全边界重构 | 212/212 |
5.4 QEMU 跨架构全套
riscv64、x86_64、aarch64、loongarch64 四个架构的 StarryOS 套件均全绿执行(写用例自跳过、读用例真实执行)。值得注意的是,QEMU 环境的块设备是 NVMe 而非 SD 卡,因此这套验证同时证明了异步读路径在第二种块设备上的正确性,与 1.1 节”改造面向所有块设备”的定位互为印证。
5.5 宿主机确定性单元测试
| PR | 测试资产 |
|---|---|
| #2135 | rdif-block 28 项;ax-fs-ng 81 项单元 + 3 项集成;nvme-driver 16 项(发布者唯一、信息冻结、DMA 一致性、通道稳定性) |
| #2256 | 生命周期交错回归(provisional 提升、安装事务回滚、终止清理)接入 axbuild 测试发现链路 |
| #2349 | 58 项完成/等待者/准入/通道背压/取消/teardown/DMA 生命周期成体系异步行为测试 |
| #2515 | scratch 资格策略 13 项(最小长度、设备边界、root/其他分区/元数据/整盘保护、未知设备拒绝、协议绑定)+ 声明解析 3 项 + 卷扫描元数据断言 |
所有并发与生命周期修复均采用红-绿验证:先证明同一测试在旧实现上稳定失败,再验证修复后通过;每个 PR 合并前全量通过 cargo xtask clippy(按影响面)与 cargo xtask test,并经 QEMU 全套与实板复验。
六、总结
工作总结
实习以星光 2 的 SD 存储链路为验证载体,完成了块设备运行时的异步化改造:任务提交块 I/O 后不再阻塞等待,而是挂起让出执行流、完成后被精确唤醒,并配套异步准入背压、跨核提交与安全取消语义;此前先以两个 PR 完成运行时生命周期治理,作为异步安全性的地基。全部工作以 6 个经评审合并的上游 PR 交付;异步路径在实板对照中取得吞吐 +36%、时延 −27% 的实证数据;同时建立了覆盖宿主机确定性单元测试、QEMU 四架构全套(NVMe 设备上真实执行)与实板 axtest(212 项)的分层验证体系。
附录:Pull Request 索引
| PR | 标题 | 链接 |
|---|---|---|
| #1954 | fix(visionfive2): restore booti and SD rootfs boot | https://github.com/rcore-os/tgoskits/pull/1954 |
| #2135 | fix(ax-fs-ng): stabilize block runtime lifecycle publication | https://github.com/rcore-os/tgoskits/pull/2135 |
| #2256 | fix(ax-fs-ng): linearize block runtime lifecycle | https://github.com/rcore-os/tgoskits/pull/2256 |
| #2349 | feat(ax-fs-ng): add async block request runtime | https://github.com/rcore-os/tgoskits/pull/2349 |
| #2451 | test(starry): add block runtime async benchmark | https://github.com/rcore-os/tgoskits/pull/2451 |
| #2515 | test(starry): extend async block runtime performance coverage | https://github.com/rcore-os/tgoskits/pull/2515 |
本人仓库:https://github.com/xianxw/tgoskits (分支说明见第二节)
实习日志:https://github.com/xianxw/StarryOS/wiki
演示视频:https://drive.google.com/file/d/1CK_Iy4NacZsds-AHafIXxjFaCdVCUqMH/view?usp=drive_link