fsnotify


linux的2.6.11内核之后有了inotify,这个特性确实很不错,使得很多用户策略得以实现,但是这个特性的代码实现却不是那么好,说实话很乱,很难扩展,很多链表,抽象出的dev结构也不是那么符合逻辑,只不过是为了将各种杂乱的数据结合在一起的勉强罢了。近期由于换工作一直没有关注kernel方面的更新,今天在新工作敲定以后终于有时间看看kernel最新的进展了,发现2.6.31版本的内核中对notify进行了一番大的改动,将原来的inotify和dnotify这两个不想关的特性进行了抽象,将它们的共同的点抽象成了一个基础设施,这个基础设施就是fsnotify.



其实,fsnotify并没有什么难于理解的,它甚至比原来的inotify和dnotify更加简单了,这次的这个更新仅仅更新了机制而没有更新策略,也就是用户接口并没有任何的变化。如果说有人理解kernel中的device和device_driver体系以及input子系统的话,那么这个fsnotify就不难理解了,它其实是将文件系统变化通知这个特性进行了解耦合的架构,抽象出了fsnotify_event和fsnotify_group数据结构,event代表了事件,可以是打开,读写,删除等等,它在具体事件发生时懒惰创建,而group代表了接收事件的策略,用户每创建一个监控通知inode,就相当于创建了一个group,然后将文件系统中要被监控的文件加入到这个group的监控列表当中,一旦有事件发生,内核就遍历所有的group,在每个group中遍历该group感兴趣的inode,一旦发现就在第一个group被发现后创建event,然后依次全部交由这些group的fsnotify_ops中的handle_event来进行实际的通知,这个handle_event是一个回调函数,不同的通知系统可以实现不同的策略,在inotify中,它的实现就是创建一个事件的holder,然后将之将event加入到该group的一个链表中,注意,此时用户空间可能有进程睡眠在该inotify相关的文件上,体现为group的一个睡眠队列,待holder加入到链表之后,最后唤醒睡眠队列上的进程。



现在注意,一个event可以对应的添加到多个group的通知链表中,同时一个文件也可以被多个group所监控,每个group都可以携带两个链表,一个是notification_list,它是被用户空间监控的holder的集合,另一个是mark_entries,它是该group感兴趣的文件inode的集合,另外一个inode拥有一个i_fsnotify_mark_entries链表,它集合了所有监控它的group。就这几个链表构成了fsnotify的基础设施,原先的硬编码的inotify很死板,现在的fsnotify将很多实体之间的耦合解除,回调函数实现具体的策略,这样可以实现很多不同的通知方式。



我认为2.6.31的这个关于notify的改进是一件大事,因为它事实上将内核的机制做的更加大气,可读性强了,可扩展性也强了,在内核发展的很长一段时间内,一些新的特性被加入到内核mainline中,起初都是硬编码的方式,到了后面几乎都会用一种更优雅的方式重写,这些优雅的方式时刻体现着软件设计的方方面面,有很多OO的思想,在此可以肯定的说,OO理论在linux内核设计方面是多的的低调啊。



Category linux