2026.3.30-2026.4.5
工作内容
- 完善用户态文件系统(FUSE)的内核态驱动,通过用户态测试(open、read)。
- 解决FUSE用户态测试中崩溃和卡死问题。
- 总结归纳文档。
本周核心代码变更总结
1. 内核挂载逻辑重构:从硬编码到动态注册
- 改动点:重构了
sys_mount系统调用,使用get_filesystem_creator动态注册机制取代了原来的if-else开关逻辑。 - 原因:
- 解耦:以前挂载新的文件系统(如 FUSE)需要在内核核心代码中手动添加逻辑。现在,FUSE 模块在被加载时(Load)会向 VFS 注册自己。
- 按需触发:当用户执行
mount -t fuse时,内核如果发现fuse类型尚未注册,可以触发ondemand机制去寻找并加载fuse.ko模块。
2. FUSE 设备阻塞 I/O 支持 (Starryfuse/src/dev.rs)
- 改动点:为
/dev/fuse字符设备添加了NodeFlags::BLOCKING标志。 - 原因:
- 解决死等问题:由于 FUSE 守护进程(Daemon)通常通过
read()等待内核发来的请求,如果不设置为阻塞模式,轮询(Poller)路径在未实现Pollable接口时会导致任务永久睡眠。 - 同步机制:按需加载的 FUSE 模块必须能正确处理来自内核的同步请求,强制阻塞确保了守护进程在到达前能正确挂起。
- 解决死等问题:由于 FUSE 守护进程(Daemon)通常通过
3. VFS 节点元数据更新 (Starryfuse/src/vfs.rs)
- 改动点:实现了
FuseNode的update_metadata方法。 - 原因:
- 资源清理:在文件 release 或 cleanup 时,内核常会尝试更新时间戳(atime/mtime)。如果不实现此接口,会导致内核抛出告警。
- 健壮性:虽然目前为了简化测试,对
chmod/chown等操作报错(取决于用户态守护进程的支持),但基础的元数据维护是模块正常卸载和资源回收的前提。
4. 模块生命周期与清理 (Starryfuse/src/lib.rs)
- 改动点:在
exit_fuse(模块退出函数)中添加了unregister_filesystem("fuse")。 - 原因:
- 防止悬空指针:按需加载意味着模块可以被动态卸载(Unload)。如果不取消注册,内核 VFS 可能会保留指向已释放内存块(模块代码段)的指针,导致系统崩溃(Kernel Panic)。
- 闭环管理:确保了模块“加载-注册-使用-注销-卸载”的完整闭环。
5. 测试守护进程的修正 (Starryfuse/tests/fuse_test/src/main.rs)
- 改动点:修正了
readdir的 offset 处理逻辑,并改用带超时的poll()而非原生read()。 - 原因:
- 修复活锁:之前的
readdir忽略了 offset,导致内核在列目录时进入无限循环。 - 支持正常卸载:使用
poll()配合超时,让守护进程能感知到文件系统已被 umount,从而主动退出并关闭/dev/fuse句柄,允许内核顺利回收 FUSE 模块。
- 修复活锁:之前的
Issue #2 解决历程
这一部分详细记录了我们在对齐远程 723fc6b 版本与当前本地最终可工作版本之间的过程。
底层 panic -> 逻辑层挂起阻塞 (卡死) -> 资源层异常反馈 -> 平稳回收释放
以下是基于 723fc6b 的完整改动总览。
| 故障类别 | 直接现象 | 根本原因 (Root Cause) | 关键修改文件 | 修复方案 | 结果 |
|---|---|---|---|---|---|
| P1: 模块代码段的 Use-After-Free | 卸载模块后系统抛出 Unhandled Supervisor Page Fault (EXECUTE)。 |
VFS 或子系统中遗留了指向该模块代码段的指针。模块释放后,控制流跳转至该野指针触发指令级缺页。 | api/src/kmod/ondemand.rsmodules/fuse/src/lib.rsapi/src/vfs/mod.rs |
1. 强化卸载条件: 仅当引用计数为零且无打开的描述符时允许卸载。 2. 清理野指针: 在 fuse_exit() 中彻底注销相关设备和资源。 |
消除了执行型缺页异常,实现了安全的动态加载/卸载闭环。 |
| P2: 守护进程 IO 挂起 (Daemon Hang) | 测试结束后守护进程持续挂起,导致模块无法卸载。 | 守护进程使用了同步阻塞型 read()。当内核不再发送请求时,进程进入永久等待,无法释放文件描述符。 |
Starryfuse/tests/fuse_test/src/main.rs |
引入 IO 多路复用机制,使用带超时的 libc::poll()。侦测到超时后主动跳出循环并安全退出。 |
守护进程通过超时机制正常退出,正确释放资源。 |
| P3: 目录读取活锁 (Readdir Livelock) | 底层日志被高频循环的 FUSE_READDIR 事件抢占。 |
用户态模块未正确处理 offset 语义,始终返回首个目录项,导致内核因收不到 EOF 标志而陷入重试读取的死循环。 |
Starryfuse/tests/fuse_test/src/main.rs |
完善状态机逻辑:收到 offset != 0 请求时回复空结构,向内核传递 EOF 信号。 |
VFS 正确识别文件末尾,终止检索并跳出死循环。 |
| P4: 字符设备 IO 阻塞语义缺失 | 设备在被 poll/select 监管时,唤醒与挂断行为不稳定。 |
/dev/fuse 驱动未向内核显式注册字符设备的阻塞属性。 |
Starryfuse/src/dev.rs |
重写 flags() 方法,显式返回 NodeFlags::BLOCKING 特征。 |
内核进程调度器正确感知节点阻塞特征,多路复用表现恢复正常。 |
| P5: VFS 元数据更新引发panic | 节点注销时频繁打印 Failed to update file times: OperationNotSupported。 |
VFS 在析构 inode 时默认尝试调用 update_metadata() 更新时间戳,而虚拟文件系统层缺乏此支持。 |
Starryfuse/src/vfs.rs |
实现兼容接口: 手动实现 update_metadata(),静默处理时间更新请求并返回 Ok(())。 |
适配了 VFS 的通用清理流程,屏蔽了不必要的磁盘同步警告。 |
| P6: 后台监控引发内核崩溃 | 后台定时检查模块空闲时,随机引发 ext4_bcache_free 异常。 |
检查器盲目遍历所有打开文件并获取路径,误触发了底层磁盘缓存操作或死锁。 | api/src/kmod/ondemand_builtin.rs |
精细化检查:优先校验文件系统类型,非内存设备 (devfs) 绝对不尝试获取路径。 |
避免了对常规系统文件的误伤,消除了随机崩溃隐患。 |
FUSE模块按需加载核心设计片段
1 | // ==================== 1. 触发点安全过滤与前置校验 ==================== |
运行测试
1 | [ 5.774269 0:11 starry_api::kmod::ondemand:43] [ondemand] module 'fuse' loaded, handle=0x17c96ff18 |
下周工作安排
- 完善benchmark,进行内核资源利用提升测试。
- 尝试接入Rust官方库提供的用户态文件系统。
- 在
Starryfuse/src/dev.rs中,为FuseDev完整实现操作系统的Pollable接口。我们需要自主提供一套合规的异步唤醒逻辑。 - 整理文档和代码仓库,准备汇报。