通过知名的机制进行监控,可以通过Linux监视目录以进行更改。 通过inotify,可以在目录上设置手表,将其配置为观看内容上的事件,当发生事件时,您将在文件描述符上收到消息。 当目录在本地存储设备(如硬盘驱动器,SSD或USB驱动器)上时,此功能非常正确,但当存储位于另一台计算机上时,该目录不在网络文件系统上。 在同一个目录中工作的另一个用户通过相同或另一个文件系统进行连接,可以删除文件,并且您在其上设置的手表将不会被通知。
为什么是这样?
通过设计,inotify获得了一个操作的结果(如mkdir或chmod),但是手表是什么样的文件系统是未知的(黑匣子)来进行操作。 文件系统不会“知道”一个手表已被设置,因此无法采取正确的动作,如通知远程主机有人想要看目录。
只要你是唯一的用户,没有问题。 当您想要观看的目录中有更多用户工作时,会出现问题。
您可以将此行为与公共库进行比较。 当你是唯一的用户时,你可以知道哪些书籍是可用的,哪些书籍不是你所知道的那样。 当你不是唯一的用户,这是不可能的,有更多的用户借用这些书。
在这种情况下,图书馆里的某些人应该管理任何用户借用的东西(这是通常的情况),你必须联系这个人来知道一本书是否可用。 这就像要求某人通知你一本当前不存在的书再次可用。
现在这个与图书馆联系通知你不适用于Linux,当然这个库是远程存储,服务器是在图书馆工作的“某人”。
为了使这个工作与Linux是使远程服务器得到通知一个手表已经设置。
实际上,像CIFS和最新版本的NFS这样的文件系统包括支持向服务器发送一个手表:对于内核4.1.2的fs / cifs / cifssmb.c的6438行的CIFS,这个(NT_TRANSACT_NOTIFY_CHANGE)的SMB消息被注释掉但仍然存在。 评论这个的原因是它与dnotify一起工作,这不是Linux的默认fsnotify系统。
使用网络文件系统在Linux上进行手表转发,通过内核空间可以实现FUSE。
最近我试图用FUSE实现这个“将手表转发到服务器”。 我不得不补丁:
fsnotify内核子系统,通知FUSE内核模块,在inode中设置或删除了一个手表。
FUSE内核模块通过fsnotify通知后采取行动。 我介绍了一个新的操作代码
FUSE_FSNOTIFY内核模块与inodenumber和mask一起发送给userspace守护程序。
FUSE库通过调用用户空间文件系统的正确功能来接收和处理FUSE_FSNOTIFY调用。
FUSE库可以接收和处理fs事件并将其报告回VFS。
仔细看看事情如何工作,当手表已经被用户空间文件系统设置在其后端成功(注意它也可以回复ENOSYS),后端可以随时在手表上发送一个事件,直到手表被删除 该活动如何处理?
可能的情况:
引入额外的FUSE操作码FUSE_FSNOTIFY_EVENT,在后台协议接收到的事件中翻译掩码,并将其发送回FUSE模块,使用新的操作码,手表的inode,条目的名称,以及翻译的面具。 FUSE模块将其发送到fsnotify子系统,该子系统通知列表(inotify和/或fanotify),其中提供了事件在后端的信息。 (需要一个额外的事件标志,例如用于暗示事件掩码IN_REMOTE,用于fanotify FAN_REMOTE)。 听众应该如何处理这些信息。 本地VFS可能已经或可能不是最新的。
笔记:
将面具从后端翻译成fsnotify的东西可以很容易,而不是那么容易,这取决于事件。 在监视的目录中创建(或删除)条目的基本事件很简单(FS_CREATE和FS_DELETE),所有者的更改也不是那么难(FS_ATTRIB),但是类似扩展属性(SMB使用那些很多)只能被翻译成通用的东西作为FS_ATTRIB。
FUSE模块应检查手表和/或inode是否仍然有效,如果手表的面罩适用于事件掩码。
需要额外的掩码位IN_REMOTE(forotify)和FAN_REMOTE(用于fanotify)。
双重信息是要避免的。 这很棘手 例如,在手表所在的主机上的监视目录中创建文件。 当这个操作成功时,这将导致一个fsnotify事件FS_CREATE,它也会创建一个FS_CREATE | FS_REMOTE事件,因为在后端执行操作成功,导致这个消息(从后端→保险丝库→FUSE内核模块→fsnotify子系统→inotify和/或fanotify)。
解决这个问题的一个方法是要求后端只发送其他人发起的事件。 对于后端,将FS事件的启动器(主机)与进行连接的主机进行比较是非常简单的。
另一个解决方案是将报告的事件与保险丝库和FUSE模块中的本地缓存进行比较。 通过创建文件的示例,库(和FUSE模块)应该检查条目是否已经存在于监视目录中。 如果没有,它不是由这个主机发起的。 对于删除,这是类似的。
对于其他事件,如文件写入或所有者已更改,此方法不够,关于远程主机(如新大小,新所有者)的更改信息必须位于远程主机发送的消息中。
如果该信息不是由后端提供的,则另一个解决方案是使守护进程代表客户端监视FS事件负责维护最近本地事件的缓存。 如果报告了一个远程事件,并且在缓存中找不到本地对等体,则由另一个主机发起。 使用特定用户的连接报告事件可能会变得棘手,其他用户可能被授权或可能不被授权接收事件。 这个缓存有多大?
我以前使用过FUSE,我认为像CIFS和NFS这样的文件系统类似。
哦,是的,还有另外一个选择:只要每5秒钟轮询一次。
Stef Bon