Inotify - 强大而简单的文件更改通知系统¶
文档由 Robert Love 于 2005 年 3 月 15 日开始编写 <rml@novell.com>
文档由 Zhang Zhen 于 2015 年 1 月 4 日更新 <zhenzhang.zhang@huawei.com>
删除了过时的接口,请参考手册页了解用户界面。
原理
- 问
为什么不将监视绑定到被监视对象的打开 fd 上?
- 答
监视与打开的 inotify 设备相关联,而不是与打开的文件相关联。 这解决了 dnotify 的主要问题:保持文件打开会锁定文件,更糟糕的是,还会锁定挂载点。 因此,Dnotify 对于具有可移动媒体的桌面系统是不可行的,因为无法卸载媒体。 监视文件不应要求它处于打开状态。
- 问
为什么使用每个实例一个 fd,而不是每个监视一个 fd?
- 答
每个监视一个 fd 很快就会消耗比允许的更多的文件描述符,比管理可行的更多的 fd,以及比最佳 select()-able 更多的 fd。 是的,root 可以提升每个进程的 fd 限制,是的,用户可以使用 epoll,但要求两者都是愚蠢且无关的要求。 监视消耗的内存比打开的文件少,因此,分离数字空间是有意义的。 当前的设计是用户空间开发人员想要的:用户初始化 inotify 一次,并添加 n 个监视,但只需要一个 fd,无需调整 fd 限制。 初始化一个 inotify 实例两千次是很愚蠢的。 如果我们可以干净地实现用户空间的偏好——我们可以,idr 层使此类事情变得微不足道——那么我们应该这样做。
还有其他好的论点。 使用单个 fd,只有一个项目可以阻塞,该项目映射到单个事件队列。 单个 fd 返回所有监视事件以及任何潜在的带外数据。 如果每个 fd 都是单独的监视,
将无法获得事件排序。 文件 foo 和文件 bar 上的事件会弹出 poll() 在两个 fd 上,但是无法分辨哪个先发生。 单个队列可以轻松地为您提供排序。 这种排序对于 Beagle 等现有应用程序至关重要。 想象一下没有排序的“mv a b ; mv b a”事件。
我们将不得不维护 n 个 fd 和 n 个带有状态的内部队列,而不是只有一个。 在内核中会更加混乱。 单个线性队列是有意义的数据结构。
用户空间开发人员更喜欢当前的 API。 例如,Beagle 的人们喜欢它。 相信我,我问过了。 这并不奇怪:谁愿意通过 select 管理和阻塞 1000 个 fd?
无法获得带外数据。
1024 仍然太低了。 ;-)
当您谈论设计一个可扩展到数千个目录的文件更改通知系统时,处理数千个 fd 似乎不是正确的接口。 它太重了。
此外,_是_可以拥有多个实例并处理多个队列,因此可以处理多个关联的 fd。 不需要每个进程一个 fd 的映射; 它是每个队列一个 fd,并且一个进程很容易需要多个队列。
- 问
为什么采用系统调用方法?
- 答
糟糕的用户空间接口是 dnotify 的第二大问题。 信号是文件通知的糟糕、糟糕的接口。 或者对于任何事情,就此而言。 从所有角度来看,理想的解决方案是基于文件描述符的解决方案,该解决方案允许基本的文件 I/O 和 poll/select。 获取 fd 和管理监视可以通过设备文件或一系列新的系统调用来完成。 我们决定实现一系列系统调用,因为这是新内核接口的首选方法。 唯一的真正区别是我们是否想使用 open(2) 和 ioctl(2) 或几个新的系统调用。 系统调用优于 ioctls。