|
每一个 watch 对应一个 inotify_watch 结构:
struct inotify_watch {
struct list_head
d_list; /* entry in inotify_device's list */
struct list_head
i_list; /* entry in inode's list */
atomic_t count;
/* reference count */
struct inotify_device *dev;
/* associated device */
struct inode *inode;
/* associated inode */
s32
wd;
/* watch descriptor */
u32 mask;
/* event mask for this watch */ };
|
d_list 指向所有 inotify_device 组成的列表的,i_list 指向所有被监视 inode 组成的列表,count 是引用计数,dev 指向该 watch 所在的 inotify 实例对应的 inotify_device 结构,inode 指向该 watch 要监视的 inode,wd 是分配给该 watch 的描述符,mask 是该 watch 的事件掩码,表示它对哪些文件系统事件感兴趣。
结构 inotify_device 在用户态调用 inotify_init() 时创建,当关闭 inotify_init()返回的文件描述符时把被释放。结构 inotify_watch 在用户态调用 inotify_add_watch()时创建,在用户态调用 inotify_rm_watch() 或 close(fd) 时被释放。
无论是目录还是文件,在内核中都对应一个 inode 结构,inotify 系统在 inode 结构中增加了两个字段:
#ifdef CONFIG_INOTIFY struct
list_head inotify_watches;
/* watches on this inode */
struct semaphore inotify_sem;
/* protects the watches list */
#endif
|
inotify_watches 是在被监视目标上的 watch 列表,每当用户调用 inotify_add_watch()时,内核就为添加的 watch 创建一个 inotify_watch 结构,并把它插入到被监视目标对应的 inode 的 inotify_watches 列表。inotify_sem 用于同步对 inotify_watches 列表的访问。当文件系统发生第一部分提到的事件之一时,相应的文件系统代码把显示调用fsnotify_* 来把相应的事件报告给 inotify 系统,其中*号就是相应的事件名,目前实现包括:
- fsnotify_move,文件从一个目录移动到另一个目录
- fsnotify_nameremove,文件从目录中删除
- fsnotify_inoderemove,自删除
- fsnotify_create,创建新文件
- fsnotify_mkdir,创建新目录
- fsnotify_access,文件被读
- fsnotify_modify,文件被写
- fsnotify_open,文件被打开
- fsnotify_close,文件被关闭
- fsnotify_xattr,文件的扩展属性被修改
- fsnotify_change,文件被修改或原数据被修改
有一个例外情况,就是 inotify_unmount_inodes,它会在文件系统被 umount 时调用来通知 umount 事件给 inotify 系统。
以上提到的通知函数最后都调用 inotify_inode_queue_event(inotify_unmount_inodes直接调用 inotify_dev_queue_event ),该函数首先判断对应的inode是否被监视,这通过查看 inotify_watches 列表是否为空来实现,如果发现 inode 没有被监视,什么也不做,立刻返回,反之,遍历 inotify_watches 列表,看是否当前的文件操作事件被某个 watch 监视,如果是,调用 inotify_dev_queue_event,否则,返回。函数inotify_dev_queue_event 首先判断该事件是否是上一个事件的重复,如果是就丢弃该事件并返回,否则,它判断是否 inotify 实例即 inotify_device 的事件队列是否溢出,如果溢出,产生一个溢出事件,否则产生一个当前的文件操作事件,这些事件通过kernel_event 构建,kernel_event 把创建一个 inotify_kernel_event 结构,然后把该结构插入到对应的 inotify_device 的 events 事件列表,然后唤醒等待在inotify_device 结构中的 wq 指向的等待队列。想监视文件系统事件的用户态进程在inotify 实例(即 inotify_init() 返回的文件描述符)上调用 read 时但没有事件时就挂在等待队列 wq 上。
四、使用示例
下面是一个使用 inotify 来监视文件系统事件的例子:
|