Skip to content

feat(fs): implement inotify filesystem event notification #2151

Description

@sparkzky

背景

ANOLISA 多个组件依赖 inotify 做响应式文件监听:

组件 用途 当前降级方案
skillfs SKILL.md 变更热重载——文件变化时自动重新解析虚拟视图 定时轮询(效率低,有延迟)
agent-memory 记忆文件变更通知——新记忆写入或更新时触发索引刷新 定时检查 mtime
copilot-shell / cosh-ng 技能/配置热重载 定时轮询

轮询是 interim 方案,体验和效率都打折。完整的 inotify 支持能让这些组件从"轮询式"变"响应式"。

DragonOS 现状

完全缺失

检查项 结果 证据
grep inotify|fanotify|fsnotifykernel/src/ 零实现命中
inotify syscall 号 有占位,无 handler kernel/src/arch/x86_64/syscall/nr.rsSYS_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.rsIndexNode 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-137file.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.rsIndexNode 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.rsdeclare_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 行。

主要难点:

  1. VFS 写路径插桩面广——每个文件系统实现的 create/unlink/rename/write 都要加通知调用
  2. watch 的生命周期管理——inode 被删除时 watch 要清理,防止悬空引用
  3. 事件排序与合并——短时间内的多次写操作需要合理合并,防止事件风暴

替代方案(interim)

在 inotify 完整实现之前,ANOLISA 侧各组件可用以下兜底:

方案 适用 代价
定时轮询 mtime skillfs / agent-memory CPU 浪费 + 检测延迟(1-5s)
FUSE NOTIFY inode invalidation skillfs(本身是 FUSE FS) 已部分可用,但只覆盖缓存失效,不覆盖"文件被修改"事件

建议:inotify 应纳入 DragonOS 路线图,但优先级低于 uprobe(agentsight 可观测闭环优先)。轮询能撑住初期。

验证标准

  1. inotify_init1() 返回有效 fd
  2. inotify_add_watch(fd, "/tmp/test", IN_ALL_EVENTS) 成功注册
  3. /tmp/test 执行 touch/echo/rmread(fd) 收到对应的 inotify_event
  4. epoll 能监听 inotify fd(EPOLLIN 在有事件时触发)
  5. skillfs 在 DragonOS 上挂载,修改 SKILL.md 后自动重新解析(无轮询延迟)

依赖关系

  • 无前置依赖——独立于 uprobe 和 execve tracepoint
  • 可与 uprobe 并行开发,分配给不同的人
  • 优先级低于 uprobe——轮询能兜底,uprobe 无替代方案

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions