Chinese (Simplified)

Note

此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。

Original:

Inotify - A Powerful yet Simple File Change Notification System

翻译:

王龙杰 Wang Longjie <wang.longjie1@zte.com.cn>

Inotify - 一个强大且简单的文件变更通知系统

文档由 Robert Love <rml@novell.com> 于 2005 年 3 月 15 日开始撰写

文档由 Zhang Zhen <zhenzhang.zhang@huawei.com> 于 2015 年 1 月 4 日更新

  • 删除了已废弃的接口,关于用户接口请参考手册页。

  1. 基本原理

问:

不将监控项与被监控对象打开的文件描述符(fd)绑定,这背后的设计决策是什么?

答:

监控项会与打开的 inotify 设备相关联,而非与打开的文件相关联。这解决了 dnotify 的主要问题: 保持文件打开会锁定文件,更糟的是,还会锁定挂载点。因此,dnotify 在带有可移动介质的桌面系统 上难以使用,因为介质将无法被卸载。监控文件不应要求文件处于打开状态。

问:

与每个监控项一个文件描述符的方式相比,采用每个实例一个文件描述符的设计决策是出于什么 考虑?

答:

每个监控项一个文件描述符会很快的消耗掉超出允许数量的文件描述符,其数量会超出实际可管理的范 围,也会超出 select() 能高效处理的范围。诚然,root 用户可以提高每个进程的文件描述符限制, 用户也可以使用 epoll,但同时要求这两者是不合理且多余的。一个监控项所消耗的内存比一个打开的文 件要少,因此将这两个数量空间分开是合理的。当前的设计正是用户空间开发者所期望的:用户只需初始 化一次 inotify,然后添加 n 个监控项,而这只需要一个文件描述符,无需调整文件描述符限制。初 始化 inotify 实例初始化两千次是很荒谬的。如果我们能够简洁地实现用户空间的偏好——而且我们 确实可以,idr 层让这类事情变得轻而易举——那么我们就应该这么做。

还有其他合理的理由。如果只有一个文件描述符,那就只需要在该描述符上阻塞,它对应着一个事件队列。 这个单一文件描述符会返回所有的监控事件以及任何可能的带外数据。而如果每个文件描述符都是一个独 立的监控项,

  • 将无法知晓事件的顺序。文件 foo 和文件 bar 上的事件会触发两个文件描述符上的 poll(), 但无法判断哪个事件先发生。而用单个队列就可以很容易的提供事件的顺序。这种顺序对现有的应用程 序(如 Beagle)至关重要。想象一下,如果“mv a b ; mv b a”这样的事件没有顺序会是什么 情况。

  • 我们将不得不维护 n 个文件描述符和 n 个带有状态的内部队列,而不是仅仅一个。这在 kernel 中 会混乱得多。单个线性队列是合理的数据结构。

  • 用户空间开发者更青睐当前的 API。例如,Beagle 的开发者们就很喜欢它。相信我,我问过他们。 这并不奇怪:谁会想通过 select 来管理以及阻塞在 1000 个文件描述符上呢?

  • 无法获取带外数据。

  • 1024 这个数量仍然太少。 ;-)

当要设计一个可扩展到数千个目录的文件变更通知系统时,处理数千个文件描述符似乎并不是合适的接口。 这太繁琐了。

此外,创建多个实例、处理多个队列以及相应的多个文件描述符是可行的。不必是每个进程对应一个文件描 述符;而是每个队列对应一个文件描述符,一个进程完全可能需要多个队列。

问:

为什么采用系统调用的方式?

答:

糟糕的用户空间接口是 dnotify 的第二大问题。信号对于文件通知来说是一种非常糟糕的接口。其实对 于其他任何事情,信号也都不是好的接口。从各个角度来看,理想的解决方案是基于文件描述符的,它允许 基本的文件 I/O 操作以及 poll/select 操作。获取文件描述符和管理监控项既可以通过设备文件来 实现,也可以通过一系列新的系统调用来实现。我们决定采用一系列系统调用,因为这是提供新的内核接口 的首选方法。两者之间唯一真正的区别在于,我们是想使用 open(2) 和 ioctl(2),还是想使用几 个新的系统调用。系统调用比 ioctl 更有优势。