GHOST系统之家 - Windows系统光盘下载网站!
当前位置:GHOST系统之家>电脑问题 > 监听风云 | Inotify 实现原理

监听风云 | Inotify 实现原理

来源:Ghost系统之家浏览:时间:2023-08-06 08:53:23

本文转载自微信公众号「Linux内核那些事」,作者songsong001。转载本文请联系Linux内核那些事公众号。

重要的数据结构

鲁迅先生说过:程序 = 数据结构 + 算法

想想如果让我们来设计 inotify 应该如何实现呢?下面来分析一下:

  • 我们知道,inotify 是用来监控文件或目录的变动事件,所以应该定义一个对象来存储被监听的文件或目录列表和它们所发生的事件列表(在内核中定义了inotify_device 对象来存储被监听的文件列表和事件列表)。
  • 另外,当对被监听的文件或目录进行读写操作时会触发相应的事件产生。所以,应该在读写操作相关的系统调用中嵌入产生事件的动作(在内核中由inotify_dev_queue_event 函数产生事件)。

在介绍 inotify 的实现前,我们先来了解下其原理。inotify 的原理如下:

当用户调用 read 或者 write 等系统调用对文件进行读写操作时,内核会把事件保存到 inotify_device对象的事件队列中,然后唤醒等待inotify 事件的进程。正所谓一图胜千言,所以我们通过下图来描述此过程:

从上图可知,当应用程序调用 read 函数读取文件的内容时,最终会调用 inotify_dev_queue_event函数来触发事件,调用栈如下:

inotify_dev_queue_event 函数主要完成两个工作:

  • 创建一个表示事件的 inotify_kernel_event 对象,并且把其插入到 inotify_device 对象的 events 列表中。
  • 唤醒正在等待 inotify 发生事件的进程,等待的进程放置在 inotify_device 对象的 wq 字段中。

上面主要涉及到两个对象,inotify_device 和 inotify_kernel_event,我们先来介绍一下这两个对象的作用。

  • inotify_device:内核使用此对象来描述一个 inotify,是 inotify 的核心对象。
  • intoify_kernel_event:内核使用此对象来描述一个事件。

我们来看看这两个对象的定义。

1. inotify_device对象

内核使用 inotify_device 来管理 inotify 监听的对象和发生的事件,其定义如下:

下面我们介绍一下各个字段的作用:

  • wq:正在等待当前 inotify 发生事件的进程列表。
  • events:保存由 inotify 监听的文件或目录所发生的事件。
  • ih:内核用来存储 inotify 监听的文件或目录,下面会介绍。
  • event_count:inotify 监听的文件或目录所发生的事件数量。
  • max_events:inotify 能够保存最大的事件数量。

下图描述了 inotify_device 对象中两个比较重要的队列(等待队列 和 事件队列):

当事件队列中有数据时,就可以通过调用 read 函数来读取这些事件。

2. inotify_kernel_event对象

内核使用 inotify_kernel_event 对象来存储一个事件,其定义如下:

可以看出,inotify_kernel_event 对象只是对 inotify_event 对象进行扩展而已,而我们在《监听风云-inotify介绍》一文中已经介绍过 inotify_event 对象。

inotify_kernel_event 对象在 inotify_event 对象的基础上增加了 list 字段和 name 字段:

  • list:用于把所有由 inotify 监听的文件或目录所发生的事件连接起来,
  • name:用于记录发生事件的文件名或目录名。

3. inotify_handle对象

在 inotify_device 对象中,有个类型为 inotify_handle 的字段 ih,这个字段主要用来存储inotify监听的文件或目录。我们来看看 inotify_handle 对象的定义:

下面来介绍一下 inotify_handle 对象的各个字段作用:

  • idr:ID生成器,用于生成被监听对象(文件或目录)的ID。
  • watches:inotify 监听的对象(文件或目录)列表。
  • in_ops:当事件发生时,被 inotify 回调的函数列表。

4. inotify_watch对象

内核使用 inotify_handle 来存储被监听的对象列表,那么被监听对象是个什么东西呢?内核中使用inotify_watch对象来表示一个被监听的对象。其定义如下:

下面介绍一下 inotify_watch 对象各个字段的作用:

  • h_list:用于把属于同一个 inotify 监听的对象连接起来。
  • i_list:由于同一个文件或目录可以被多个 inotify 监听,所以使用此字段来把所有监听同一个文件的 inotify_handle对象连接起来。
  • ih:指向其所属的 inotify_handle 对象。
  • inode:由于在 Linux 内核中,每个文件或目录都由一个 inode 对象来描述,这个字段就是指向被监听的文件或目录的 inode 对象。
  • wd:被监听对象的ID(或称为描述符)。
  • mask:被监听的事件类型(在《监听风云 - inotify介绍》一文中已经介绍)。

现在,我们通过下图来描述一下 inotify_device、inotify_handle 和 inotify_watch 三者的关系:

inotify功能实现

上面我们把 inotify 功能涉及的所有数据结构都介绍了,有上面的基础,现在我们可以开始分析 inotify 功能的实现了。

1. inotify_init 函数

在《监听风云 - inotify介绍》一文中介绍过,要使用 inotify 功能,首先要调用 inotify_init 函数创建一个inotify的句柄,而 inotify_init 函数最终会调用内核函数 sys_inotify_init。我们来分析一下sys_inotify_init的实现:

sys_inotify_init 函数主要完成以下几个工作:

  • 调用 get_unused_fd 函数从进程中获取一个没被使用的文件描述符(句柄)。
  • 调用 get_empty_filp 获取一个文件对象。
  • 调用 kmalloc 函数申请一个 inotify_device 对象。
  • 调用 inotify_init 函数创建并初始化一个 inotify_handle 对象。
  • 把 inotify_handle 对象与 inotify_device 对象进行绑定。
  • 设置文件对象的操作函数列表为:inotify_fops,主要提供 read 和 poll 等接口的实现。
  • 将 inotify_device 对象绑定到文件对象的 private_data 字段中。
  • 把文件描述符与文件对象进行映射。
  • 返回文件描述符给应用层。

从上面的实现可以看出,sys_inotify_init 函数主要是创建 inotify_device 对象和inotify_handle对象,并且将它们与文件对象关联起来。

另外需要注意的是,在 sys_inotify_init 函数中,还把文件对象的操作函数集设置为 inotify_fops,主要提供了 read 和poll等接口的实现,其定义如下:

所以,当调用 read 函数读取 inotify 的句柄时,就会触发调用 inotify_read 函数读取 inotify 事件队列中的事件。

2. inotify_add_watch 函数

当调用 inotify_init 函数创建好 inotify 句柄后,就可以通过调用 inotify_add_watch 函数向inotify句柄添加要监控的文件或目录。inotify_add_watch 函数的实现如下:

sys_inotify_add_watch 函数主要完成以下几个工作:

  • 调用 fget_light 函数获取 inotify 句柄对应的文件对象。
  • 调用 find_inode 函数获取 path 路径对应的 inode 对象,也就是获取要监听的文件或目录所对应的 inode 对象。
  • 从 inotify 文件对象的 private_data 字段中,获取对应的 inotify_device 对象。
  • 调用 create_watch 函数创建一个新的 inotify_watch 对象,并且把这个 inotify_watch 对象添加到inotify_handle 对象的 watches 列表和 inode 对象的 inotify_watches 列表中。

事件通知

到了 inotify 最关键的部分,就是 inotify 的事件是怎么产生的。

在本文的第一部分中介绍过,当用户调用 read 系统调用读取文件内容时,最终会调用inotify_dev_queue_event函数来产生一个事件,我们先来回顾一下 read 系统调用的调用栈:

下面我们来分析一下 inotify_dev_queue_event 函数的实现:

我们先来介绍一下 inotify_dev_queue_event 函数各个参数的意义:

  • w:被监听对象,用于描述被监听的文件或目录。
  • wd:被监听对象的ID。
  • mask:发生的事件类型,可以参考《监听风云 - inotify介绍》一文。
  • cookie:比较少使用,忽略。
  • name:发生事件的文件或目录名称。
  • ignored:发生事件的文件或目录的 inode 对象,在本函数中没有使用。

inotify_dev_queue_event 函数主要完成以下几个工作:

  • 通过调用 kernel_event 函数申请一个 inotify_kernel_event 事件对象。
  • 增加 inotify 事件队列的计数器。
  • 增加 inotify 事件队列所占用的内存大小。
  • 把第一步创建的事件对象添加到 inotify 的事件队列中。
  • 唤醒正在等待读取事件的进程(因为已经有事件发生了)。

从上面的分析可以看出,inotify_dev_queue_event 函数只负责创建一个事件对象,并且添加到inotify的事件队列中。但发生了什么事件是由哪个步骤指定的呢?

我们可以通过分析 read 系统调用的调用栈,会发现在 fsnotify_access 函数中指定了事件的类型,我们来看看fsnotify_access函数的实现:

从上面的分析可知,当发生读事件时,由 fsnotify_access 函数指定事件类型为IN_ACCESS。在include/linux/fsnotify.h 文件中还实现了其他事件的触发函数,有兴趣的可以自行查阅此文件 。

总结

inotify 的实现过程总结为以下两点:

当用户调用读写、创建或删除文件的系统调用时,内核会注入相应的事件触发函数来产生一个事件,并且添加到 inotify 的事件队列中。

唤醒等待读取事件的进程,当进程被唤醒后,就可以通过调用 read 函数来读取 inotify 事件队列中的事件。

推荐系统

  • 电脑公司Ghost Win8.1 x32 精选纯净版2022年7月(免激活) ISO镜像高速下载

    电脑公司Ghost Win8.1 x32 精选纯净版2022年7月(免激活) ISO镜像高速下载

    语言:中文版系统大小:2.98GB系统类型:Win8

    电脑公司Ghost Win8.1x32位纯净版V2022年7月版本集成了自2022流行的各种硬件驱动,首次进入系统即全部硬件已安装完毕。电脑公司Ghost Win8.1x32位纯净版具有更安全、更稳定、更人性化等特点。集成最常用的装机软件,精心挑选的系统维护工具,加上绿茶独有

  • 微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载

    微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载

    语言:中文版系统大小:5.13GB系统类型:Win11

    微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Win11 64位 Office办公版(免费)优化  1、保留 Edge浏览器。  2、隐藏“操作中心”托盘图标。  3、保留常用组件(微软商店,计算器,图片查看器等)。  5、关闭天气资讯。 

  • Win11 21H2 官方正式版下载_Win11 21H2最新系统免激活下载

    Win11 21H2 官方正式版下载_Win11 21H2最新系统免激活下载

    语言:中文版系统大小:4.75GB系统类型:Win11

    Ghost Win11 21H2是微软在系统方面技术积累雄厚深耕多年,Ghost Win11 21H2系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Ghost Win11 21H2是微软最新发布的KB5019961补丁升级而来的最新版的21H2系统,以Windows 11 21H2 22000 1219 专业版为基础进行优化,保持原汁原味,系统流畅稳定,保留常用组件

  • windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载

    windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载

    语言:中文版系统大小:5.31GB系统类型:Win11

    windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载,微软win11发布快大半年了,其中做了很多次补丁和修复一些BUG,比之前的版本有一些功能上的调整,目前已经升级到最新版本的镜像系统,并且优化了自动激活,永久使用。windows11中文版镜像国内镜像下载地址微软windows11正式版镜像 介绍:1、对函数算法进行了一定程度的简化和优化

  • 微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载

    微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载

    语言:中文版系统大小:5.31GB系统类型:Win11

    微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载,微软2022年正式推出了win11系统,很多人迫不及待的要体验,本站提供了最新版的微软Windows11正式版系统下载,微软windows11正式版镜像 是一款功能超级强大的装机系统,是微软方面全新推出的装机系统,这款系统可以通过pe直接的完成安装,对此系统感兴趣,想要使用的用户们就快来下载

  • 微软windows11系统下载 微软原版 Ghost win11 X64 正式版ISO镜像文件

    微软windows11系统下载 微软原版 Ghost win11 X64 正式版ISO镜像文件

    语言:中文版系统大小:0MB系统类型:Win11

    微软Ghost win11 正式版镜像文件是一款由微软方面推出的优秀全新装机系统,这款系统的新功能非常多,用户们能够在这里体验到最富有人性化的设计等,且全新的柔软界面,看起来非常的舒服~微软Ghost win11 正式版镜像文件介绍:1、与各种硬件设备兼容。 更好地完成用户安装并有效地使用。2、稳定使用蓝屏,系统不再兼容,更能享受无缝的系统服务。3、为

  • 雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载

    雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载

    语言:中文版系统大小:4.75GB系统类型:

    雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载在系统方面技术积累雄厚深耕多年,打造了国内重装系统行业的雨林木风品牌,其系统口碑得到许多人认可,积累了广大的用户群体,雨林木风是一款稳定流畅的系统,一直以来都以用户为中心,是由雨林木风团队推出的Windows11国内镜像版,基于国内用户的习惯,做了系统性能的优化,采用了新的系统

  • 雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO

    雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO

    语言:中文版系统大小:5.91GB系统类型:Win7

    雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO在系统方面技术积累雄厚深耕多年,加固了系统安全策略,雨林木风win7旗舰版系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。win7 32位旗舰装机版 v2019 05能够帮助用户们进行系统的一键安装、快速装机等,系统中的内容全面,能够为广大用户