Linux --- inotify 文件系统变化通知机制

在linux下开发过程中,用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备,给用户提供更好的服务,如 hotplug、udev 和 inotify 就是这种需求催生的。
Hotplug 是一种内核向用户态应用通报关于热插拔设备一些事件发生的机制,桌面系统能够利用它对设备进行有效的管理,udev 动态地维护 /dev 下的设备文件
inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,该机制是著名的桌面搜索引擎项目beagle 引入的,并在 Gamin 等项目中被应用。

事实上,在 inotify 之前已经存在一种类似的机制叫 dnotify,但是它存在许多缺陷:
1. 对于想监视的每一个目录,用户都需要打开一个文件描述符,因此如果需要监视的目录较多,将导致打开许多文件描述符,特别是,如果被监视目录在移动介质上(如光盘和 USB 盘),将导致无法 umount 这些文件系统,因为使用 dnotify 的应用打开的文件描述符在使用该文件系统。
2. dnotify 是基于目录的,它只能得到目录变化事件,当然在目录内的文件的变化会影响到其所在目录从而引发目录变化事件,但是要想通过目录事件来得知哪个文件变化,需要缓存许多 stat 结构的数据。
3. Dnotify 的接口非常不友好,它使用 signal。
Inotify 是为替代 dnotify 而设计的,它克服了 dnotify 的缺陷,提供了更好用的,简洁而强大的文件变化通知机制:
1. Inotify 不需要对被监视的目标打开文件描述符,而且如果被监视目标在可移动介质上,那么在 umount 该介质上的文件系统后,被监视目标对应的 watch 将被自动删除,并且会产生一个 umount 事件。
2. Inotify 既可以监视文件,也可以监视目录。
3. Inotify 使用系统调用而非 SIGIO 来通知文件系统事件。
4. Inotify 使用文件描述符作为接口,因而可以使用通常的文件 I/O 操作select 和 poll 来监视文件系统的变化。

1、Android 对于inotify的使用情况

以上就是android中主要实现代码,层次很简单都只有一个文件

2、inotify 用户接口使用
在用户态,inotify 通过三个系统调用和在返回的文件描述符上的文件 I/O 操作来使用
创建 inotify 实例:

int fd = inotify_init ();

每一个 inotify 实例对应一个独立的排序的队列。
文件系统的变化事件被称做 watches 的一个对象管理,每一个 watch 是一个二元组(目标,事件掩码),目标可以是文件或目录,事件掩码表示应用希望关注的 inotify 事件,每一个位对应一个 inotify 事件。Watch 对象通过 watch描述符引用,watches 通过文件或目录的路径名来添加。目录 watches 将返回在该目录下的所有文件上面发生的事件。

添加一个watch:

int wd = inotify_add_watch (fd, path, mask);

fd 是 inotify_init() 返回的文件描述符,path 是被监视的目标的路径名(即文件名或目录名),mask 是事件掩码, 
在头文件 linux/inotify.h 中定义了每一位代表的事件。可以使用同样的方式来修改事件掩码,即改变希望被通知的inotify 事件。wd 是 watch 描述符。

删除一个 watch:

int ret = inotify_rm_watch (fd, wd);

文件事件变化的读取:
struct inotify_event {
        __s32           wd;             /* watch descriptor */
        __u32           mask;           /* watch mask */
        __u32           cookie;         /* cookie to synchronize two events */
        __u32           len;            /* length (including nulls) of name */
        char            name[0];        /* stub for possible name */
};

结构中的 wd 为被监视目标的 watch 描述符,mask 为事件掩码,len 为 name字符串的长度,name 为被监视目标的路径名,该结构的 name 字段为一个桩,它只是为了用户方面引用文件名,文件名是变长的,它实际紧跟在该结构的后面,文件名将被 0 填充以使下一个事件结构能够 4 字节对齐。注意,len 也把填充字节数统计在内。
通过 read 调用可以一次获得多个事件,只要提供的 buf 足够大。

size_t len = read (fd, buf, BUF_LEN);

buf 是一个 inotify_event 结构的数组指针,BUF_LEN 指定要读取的总长度,buf 大小至少要不小于 BUF_LEN,该调用返回的事件数取决于 BUF_LEN 以及事件中文件名的长度。Len 为实际读去的字节数,即获得的事件的总长度。可以在函数 inotify_init() 返回的文件描述符 fd 上使用 select() 或poll(), 也可以在 fd 上使用 ioctl 命令 FIONREAD 来得到当前队列的长度。close(fd)将删除所有添加到 fd 中的 watch 并做必要的清理。

总结整体用法:

[cpp] view plaincopy print?
  1. int fd = inotify_init();
  2. wfd = inotify_add_watch(fd, path, mask);
  3. for(;;){// 可以使用 select() / poll() 进行轮询
  4. char event_buf[512];
  5. struct inotify_event* event;
  6. int num_bytes = read(fd, event_buf, sizeof(event_buf));
  7. while (num_bytes >= (int)sizeof(*event)){
  8. int event_size;
  9. event = (struct inotify_event *)(event_buf + event_pos);
  10. //TODO 可以返回正在监控的 event->wd, event->mask ,event->name(path)
  11. event_size = sizeof(*event) + event->len;
  12. num_bytes -= event_size;
  13. event_pos += event_size;
  14. }
  15. }
  16. inotify_rm_watch(fd, wfd);

3、内核实现机理

源码在:
fs\notify\inotify\inotify.c
fs\notify\inotify\inotify_user.c

先看重要的几个数据数据

[cpp] view plaincopy print?
  1. struct inotify_device {
  2. wait_queue_head_t       wq;             /* wait queue for i/o */
  3. struct idr              idr;            /* idr mapping wd -> watch */
  4. struct semaphore        sem;            /* protects this bad boy */
  5. struct list_head        events;         /* list of queued events */
  6. struct list_head        watches;        /* list of watches */
  7. atomic_t                count;          /* reference count */
  8. struct user_struct      *user;          /* user who opened this dev */
  9. unsigned int            queue_size;     /* size of the queue (bytes) */
  10. unsigned int            event_count;    /* number of pending events */
  11. unsigned int            max_events;     /* maximum number of events */
  12. u32                     last_wd;        /* the last wd allocated */
  13. };

在内核中,每一个 inotify 实例对应一个 inotify_device 结构,这个里面有个重要的东东:idr其功能:idr 用于把 watch 描述符映射到对应的 inotify_watch ,如此对于wfd就有具体的描述符才能实现监控。这个 idr 是在 inotify_add_watch 中调用 idr_get_new_above 将 idr 与 wfd 进行映射的

所谓IDR,其实就是和身份证的含义差不多,我们知道,每个人有一个身份证,身份证只是 一串数字,从数字,我们就能知道这个人的信息。同样道理,idr的要完成的任务是给要管理的对象分配一个数字,可以通过这个数字找到要管理的对象。

events 为该 inotify 实例上发生的事件的列表,被该 inotify 实例监视的所有事件在发生后都将插入到这个列表,watches 是给 inotify 实例监视的 watch 列表,inotify_add_watch 将把新添加的 watch 插入到该列表

每一个 watch 对应一个 inotify_watch 结构:

[cpp] view plaincopy print?
  1. struct inotify_watch {
  2. struct list_head        d_list; /* entry in inotify_device's list */
  3. struct list_head        i_list; /* entry in inode's list */
  4. atomic_t                count;  /* reference count */
  5. struct inotify_device   *dev;   /* associated device */
  6. struct inode            *inode; /* associated inode */
  7. s32                     wd;     /* watch descriptor */
  8. u32                     mask;   /* event mask for this watch */
  9. };

d_list 指向所有 inotify_device 组成的列表的,i_list 指向所有被监视 inode 组成的列表,count 是引用计数,dev 指向该 watch 所在的 inotify 实例对应的 inotify_device 结构,inode 指向该 watch 要监视的 inode,wd 是分配给该 watch 的描述符,mask 是该 watch 的事件掩码,表示它对哪些文件系统事件感兴趣。

基本的数据结构理清楚,代码明了不介绍了。
还有一个问题就是如何对sdcard做到unmount事件通知呢?其实就是在内核中有个函数: inotify_unmount_inodes
它会在文件系统被 umount 时调用来通知 umount 事件给 inotify 系统

linux --- inotify 文件系统变化通知机制相关推荐

  1. Linux inotify功能及原理(inotify_init、inotify_add_watch、inotify_rm_watch、read)

    1. inotify主要功能 它是一个内核用于通知用户空间程序文件系统变化的机制. 开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备 ...

  2. Linux inotify功能及实现原理【转】

    转自:http://blog.csdn.net/myarrow/article/details/7096460 1. inotify主要功能 它是一个内核用于通知用户空间程序文件系统变化的机制. 众所 ...

  3. Linux Inotify详解

    本文转自 https://blog.csdn.net/longwang155069/article/details/54016789 描述 Inotify API用于检测文件系统变化的机制.Inoti ...

  4. inotify 文件系统监控

    对于目录监听底层通过 inotify机制实现,inotify 是在 2.6.13 中引入的新功能,它为用户态监视文件系统的变化提供了强大的支持;inotify 是一种文件系统的变化通知机制,如文件增加 ...

  5. PHP Linux监控文件变化,文件监控与通知机制 audit inotify

    什么是auditThe Linux Audit Subsystem is a system to Collect information regarding events occurring on t ...

  6. linux inotify 监控文件系统事件

    1. Inotify 机制概述 1.1. Inotify 介绍 在日常的运维过程中,经常需要备份某些文件,或者对系统的某些文件进行监控,比如重要的配置文件等.如果需要作到实时同步或者监控,就需要使用内 ...

  7. Linux内核中断引入用户空间(异步通知机制)【转】

    转自:http://blog.csdn.net/kingdragonfly120/article/details/10858647 版权声明:本文为博主原创文章,未经博主允许不得转载. 当Linux内 ...

  8. Linux inotify

    简述 Linux inotify是一种监控文件系统中文件和目录变化的机制,能够实时地监视文件和目录的变化并通知相应的进程. 在Linux系统中,文件系统的访问和管理是通过系统调用进行的.inotify ...

  9. Linux Ext 文件系统

    引言 本文整理了 Linux 内核中 Ext 文件系统的相关知识.更多相关文章和其他文章均收录于贝贝猫的文章目录. 文件系统种类 前面我们讨论了虚拟文件系统,它对所有下层文件系统进行了封装,统一了上层 ...

最新文章

  1. 动手动脑问题2加课堂练习
  2. 图书管理系统c++_校园图书系统写后感
  3. 使用xshell上传本地文件到服务器
  4. 亚马逊面试有几轮_经过几个月的Google面试准备,我被亚马逊录用
  5. java数组怎么倒循环_java – 用于数组倒计时的反向循环
  6. SSM整合框架实现发送邮件功能
  7. php 显示状态,php-fpm status状态配置显示
  8. tar解压失败:gzip: stdin: not in gzip format
  9. mysql mybatis 主键id_MyBatis+MySQL 返回插入的主键ID
  10. 无线打印 airprint 服务器,怎么设置普通打印机也能airprint无线打印
  11. 安卓程序员需要什么证书
  12. 80286计算机配置,电脑的各种配置给详的细解释.doc
  13. python中plt.cm.Paired
  14. Powershell 添加开机启动项
  15. python(3.10,Win10 64位)的wordcloud安装
  16. 教师人生格言积极向上的句子
  17. 着眼未来 巅峰对决 | “智算之道—2020人工智能应用挑战赛”圆满收官!
  18. 停!别盲目跟风学Python了!网友:我太难了...
  19. linux双击运行jar包,linux下发布JAR包 并运行
  20. 在MATLAB中调用 Python

热门文章

  1. GitLab容器注册服务已集成于Docker容器
  2. 从DLL导出.a文件
  3. 计算机网络知识学习(核心:网络协议)-- 运输层
  4. 机器学习之集成算法----Adaboost算法
  5. [Windows] 集福宝- 支付宝 集福神器 2019
  6. java 可变参数列表 数组_java可变参数列表如何填充数组?
  7. java 汾_Javaweb学习 4
  8. 为什么要避免不可重复读_浅谈游戏的耐玩性-玩家为什么要重复打开你的游戏?...
  9. postman导出请求url_postman接口测试之复制多个接口或collections到某个子文件夹或collections下...
  10. 中心点 unity_32-Unity入门学习11「UI锚点与自适应」