背景
ANOLISA 多个组件依赖 inotify 做响应式文件监听:
| 组件 |
用途 |
当前降级方案 |
| skillfs |
SKILL.md 变更热重载——文件变化时自动重新解析虚拟视图 |
定时轮询(效率低,有延迟) |
| agent-memory |
记忆文件变更通知——新记忆写入或更新时触发索引刷新 |
定时检查 mtime |
| copilot-shell / cosh-ng |
技能/配置热重载 |
定时轮询 |
轮询是 interim 方案,体验和效率都打折。完整的 inotify 支持能让这些组件从"轮询式"变"响应式"。
DragonOS 现状
完全缺失
| 检查项 |
结果 |
证据 |
grep inotify|fanotify|fsnotify 在 kernel/src/ |
零实现命中 |
|
| inotify syscall 号 |
有占位,无 handler |
kernel/src/arch/x86_64/syscall/nr.rs:SYS_INOTIFY_INIT=253, ADD_WATCH=254, RM_WATCH=255, INIT1=294 |
SyscallTable 注册 |
无 inotify 注册 |
kernel/src/syscall/table.rs:512-entry 表,通过 declare_syscall! 宏注册 |
| VFS 层 fsnotify hook |
零 |
kernel/src/filesystem/vfs/mod.rs:IndexNode trait 的 poll/read/write/create/unlink 等操作均无通知钩子 |
FMODE_NONOTIFY 标志 |
有定义,无使用 |
kernel/src/filesystem/vfs/file.rs:470-471(注释提及 fanotify) |
现有相关机制(可作为参考或兜底)
| 机制 |
文件 |
状态 |
| epoll |
kernel/src/filesystem/epoll/event_poll.rs |
完整,但 regular file 无事件源(仅 pipe/socket/eventfd/signalfd 有意义) |
| eventfd |
kernel/src/filesystem/eventfd.rs |
完整,可作为伪文件系统参考 |
| signalfd |
kernel/src/ipc/signalfd.rs |
完整,含 epoll 集成和 hardirq-safe 通知 |
| FUSE NOTIFY |
kernel/src/filesystem/fuse/conn/daemon.rs:788-828 |
部分已实现:INVAL_INODE/INVAL_ENTRY/DELETE 可用;POLL/STORE/RETRIEVE 返回 EOPNOTSUPP |
| FUSE inode 通知 |
kernel/src/filesystem/fuse/inode/directory.rs:115-137、file.rs:87-141 |
notify_invalidate_child/notify_invalidate_pages 可用 |
VFS 层结构
DragonOS VFS 以 IndexNode trait 为中心(Rust trait object),各文件系统实现此 trait。通知机制的缺失意味着每个写操作路径(create/unlink/rename/write)都没有任何通知调用点。
无 anon_inode 框架——eventfd/signalfd 各自实现伪文件系统,应抽取公共框架。
实现计划
步骤 1:设计 fsnotify 统一通知层
新建 kernel/src/filesystem/fsnotify/(参考 Linux fs/notify/):
fsnotify_group:代表一个通知监听者(inotify instance 对应一个 group)
fsnotify_mark:一个监听标记(一个 watch 对应一个 mark),关联到某个 inode
Notification trait 或枚举:统一的事件类型(create/delete/modify/move/close_write...)
这是 Linux 的做法——inotify 和 fanotify 共享 fsnotify 底层。DragonOS 应照搬此抽象,即使目前只做 inotify。
步骤 2:在 VFS 写路径插入通知调用
修改 kernel/src/filesystem/vfs/mod.rs 的 IndexNode trait 实现,在以下操作路径插入 fsnotify() 调用:
| 操作 |
事件 |
通知对象 |
create |
IN_CREATE |
父目录的 watch |
unlink |
IN_DELETE |
父目录的 watch |
rename |
IN_MOVE |
源和目标父目录 |
write |
IN_MODIFY |
文件本身的 watch |
| close (writable) |
IN_CLOSE_WRITE |
文件的 watch |
这是改动面最广的部分——每个文件系统实现(ext4/tmpfs/overlayfs)的这些操作都需要触发通知。
步骤 3:实现 inotify 设备
新建 kernel/src/filesystem/inotify.rs:
inotify_init1() → 创建 InotifyGroup(通过 anon_inode 暴露为 fd)
inotify_add_watch() → 注册 mark 到目标 inode
inotify_rm_watch() → 移除 mark
read() → 从 event queue 读取 inotify_event 结构
步骤 4:注册 syscall
在 kernel/src/syscall/table.rs 用 declare_syscall! 注册 4 个 handler:
sys_inotify_init (253)
sys_inotify_add_watch (254)
sys_inotify_rm_watch (255)
sys_inotify_init1 (294)
步骤 5:anon_inode 框架
抽取公共 anon_inode 框架(eventfd/signalfd/inotify 共用),替代各自独立的伪文件系统实现。
要碰的子系统清单
kernel/src/filesystem/fsnotify/ (NEW — 统一通知层)
kernel/src/filesystem/inotify.rs (NEW — inotify 设备实现)
kernel/src/filesystem/vfs/mod.rs (修改 — IndexNode 写路径插 fsnotify 调用)
kernel/src/filesystem/vfs/file.rs (修改 — close 路径通知)
kernel/src/syscall/table.rs (修改 — 注册 4 个 syscall)
kernel/src/filesystem/anon_inode (NEW 或重构 — 公共伪文件系统框架)
各文件系统实现 (修改 — ext4/tmpfs/overlayfs 写路径)
复杂度评估
中大。约 2000-3000 行。
主要难点:
- VFS 写路径插桩面广——每个文件系统实现的 create/unlink/rename/write 都要加通知调用
- watch 的生命周期管理——inode 被删除时 watch 要清理,防止悬空引用
- 事件排序与合并——短时间内的多次写操作需要合理合并,防止事件风暴
替代方案(interim)
在 inotify 完整实现之前,ANOLISA 侧各组件可用以下兜底:
| 方案 |
适用 |
代价 |
| 定时轮询 mtime |
skillfs / agent-memory |
CPU 浪费 + 检测延迟(1-5s) |
| FUSE NOTIFY inode invalidation |
skillfs(本身是 FUSE FS) |
已部分可用,但只覆盖缓存失效,不覆盖"文件被修改"事件 |
建议:inotify 应纳入 DragonOS 路线图,但优先级低于 uprobe(agentsight 可观测闭环优先)。轮询能撑住初期。
验证标准
inotify_init1() 返回有效 fd
inotify_add_watch(fd, "/tmp/test", IN_ALL_EVENTS) 成功注册
- 对
/tmp/test 执行 touch/echo/rm,read(fd) 收到对应的 inotify_event
- epoll 能监听 inotify fd(
EPOLLIN 在有事件时触发)
- skillfs 在 DragonOS 上挂载,修改 SKILL.md 后自动重新解析(无轮询延迟)
依赖关系
- 无前置依赖——独立于 uprobe 和 execve tracepoint
- 可与 uprobe 并行开发,分配给不同的人
- 优先级低于 uprobe——轮询能兜底,uprobe 无替代方案
背景
ANOLISA 多个组件依赖 inotify 做响应式文件监听:
轮询是 interim 方案,体验和效率都打折。完整的 inotify 支持能让这些组件从"轮询式"变"响应式"。
DragonOS 现状
完全缺失
grep inotify|fanotify|fsnotify在kernel/src/kernel/src/arch/x86_64/syscall/nr.rs:SYS_INOTIFY_INIT=253,ADD_WATCH=254,RM_WATCH=255,INIT1=294SyscallTable注册kernel/src/syscall/table.rs:512-entry 表,通过declare_syscall!宏注册kernel/src/filesystem/vfs/mod.rs:IndexNodetrait 的poll/read/write/create/unlink等操作均无通知钩子FMODE_NONOTIFY标志kernel/src/filesystem/vfs/file.rs:470-471(注释提及 fanotify)现有相关机制(可作为参考或兜底)
kernel/src/filesystem/epoll/event_poll.rskernel/src/filesystem/eventfd.rskernel/src/ipc/signalfd.rskernel/src/filesystem/fuse/conn/daemon.rs:788-828INVAL_INODE/INVAL_ENTRY/DELETE可用;POLL/STORE/RETRIEVE返回EOPNOTSUPPkernel/src/filesystem/fuse/inode/directory.rs:115-137、file.rs:87-141notify_invalidate_child/notify_invalidate_pages可用VFS 层结构
DragonOS VFS 以
IndexNodetrait 为中心(Rust trait object),各文件系统实现此 trait。通知机制的缺失意味着每个写操作路径(create/unlink/rename/write)都没有任何通知调用点。无 anon_inode 框架——eventfd/signalfd 各自实现伪文件系统,应抽取公共框架。
实现计划
步骤 1:设计 fsnotify 统一通知层
新建
kernel/src/filesystem/fsnotify/(参考 Linuxfs/notify/):fsnotify_group:代表一个通知监听者(inotify instance 对应一个 group)fsnotify_mark:一个监听标记(一个 watch 对应一个 mark),关联到某个 inodeNotificationtrait 或枚举:统一的事件类型(create/delete/modify/move/close_write...)步骤 2:在 VFS 写路径插入通知调用
修改
kernel/src/filesystem/vfs/mod.rs的IndexNodetrait 实现,在以下操作路径插入fsnotify()调用:createunlinkrenamewrite这是改动面最广的部分——每个文件系统实现(ext4/tmpfs/overlayfs)的这些操作都需要触发通知。
步骤 3:实现 inotify 设备
新建
kernel/src/filesystem/inotify.rs:inotify_init1()→ 创建InotifyGroup(通过 anon_inode 暴露为 fd)inotify_add_watch()→ 注册 mark 到目标 inodeinotify_rm_watch()→ 移除 markread()→ 从 event queue 读取inotify_event结构步骤 4:注册 syscall
在
kernel/src/syscall/table.rs用declare_syscall!注册 4 个 handler:sys_inotify_init(253)sys_inotify_add_watch(254)sys_inotify_rm_watch(255)sys_inotify_init1(294)步骤 5:anon_inode 框架
抽取公共 anon_inode 框架(eventfd/signalfd/inotify 共用),替代各自独立的伪文件系统实现。
要碰的子系统清单
复杂度评估
中大。约 2000-3000 行。
主要难点:
替代方案(interim)
在 inotify 完整实现之前,ANOLISA 侧各组件可用以下兜底:
建议:inotify 应纳入 DragonOS 路线图,但优先级低于 uprobe(agentsight 可观测闭环优先)。轮询能撑住初期。
验证标准
inotify_init1()返回有效 fdinotify_add_watch(fd, "/tmp/test", IN_ALL_EVENTS)成功注册/tmp/test执行touch/echo/rm,read(fd)收到对应的inotify_eventEPOLLIN在有事件时触发)依赖关系