您的位置 首页 电子

需求了解的Linux inotify功能及完成原理

需要了解的Linux inotify功能及实现原理-众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备,给用户提供更好的服务,如 hotplug、udev 和 inotify 就是这种需求催生的。

1. inotify主要功能

它是一个内核用于告诉用户空间程序文件体系改动的机制。

众所周知,Linux 桌面体系与 MAC 或 Windows 比较有许多不如人意的当地,为了改进这种情况,开源社区提出用户态需求内核供给一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,然后能够更好地办理设备,给用户供给更好的服务,如 hotplug、udev 和 inoTIfy 便是这种需求催生的。Hotplug 是一种内核向用户态运用通报关于热插拔设备一些事情发生的机制,桌面体系能够运用它对设备进行有用的办理,udev 动态地保护 /dev 下的设备文件,inoTIfy 是一种文件体系的改动告诉机制,如文件增加、删去等事情能够马上让用户态得知,该机制是闻名的桌面搜索引擎项目 beagle 引进的,并在 Gamin 等项目中被运用。

2. 用户接口

在用户态,inoTIfy 经过三个体系调用和在回来的文件描述符上的文件 I/ 操作来运用,运用 inoTIfy 的榜首步是创立 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);
    fd 是 inotify_init() 回来的文件描述符,wd 是 inotify_add_watch() 回来的 watch 描述符。Ret 是函数的回来值。

文件事情用一个 inotify_event 结构表明,它经过由 inotify_init() 回来的文件描述符运用一般文件读取函数 read 来取得

: 

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 并做必要的整理。

int inotify_init (void); int inotify_add_watch (int fd, const char *path, __u32 mask); int inotify_rm_watch (int fd, __u32 mask);

3. 内核完成原理

在内核中,每一个 inotify 实例对应一个 inotify_device 结构:

struct inotify_device { wait_queue_head_t wq; /* wait queue for i/o */ struct idr idr; /* idr mapping wd -> watch */ struct semaphore sem; /* protects this bad boy */ struct list_head events; /* list of queued events */ struct list_head watches; /* list of watches */ atomic_t count; /* reference count */ struct user_struct *user; /* user who opened this dev */ unsigned int queue_size; /* size of the queue (bytes) */ unsigned int event_count; /* number of pending events */ unsigned int max_events; /* maximum number of events */ u32 last_wd; /* the last wd allocated */};

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 结构中增加了两个字段:

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_INOTIFYstruct list_headinotify_watches; /* watches on this inode */struct semaphoreinotify_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 上。

4. 运用示例

下面是一个运用 inotify 来监督文件体系事情的比如:

#include #include #include _syscall0(int, inotify_init)_syscall3(int, inotify_add_watch, int, fd, const char *, path, __u32, mask)_syscall2(int, inotify_rm_watch, int, fd, __u32, mask)char * monitored_files[] = {“./tmp_file”,”./tmp_dir”,”/mnt/sda3/windows_file”};struct wd_name {int wd;char * name;};#define WD_NUM 3struct wd_name wd_array[WD_NUM];char * event_array[] = {“File was accessed”,”File was modified”,”File attributes were changed”,”writtable file closed”,”Unwrittable file closed”,”File was opened”,”File was moved from X”,”File was moved to Y”,”Subfile was created”,”Subfile was deleted”,”Self was deleted”,”Self was moved”,””,”Backing fs was unmounted”,”Event queued overflowed”,”File was ignored”};#define EVENT_NUM 16#define MAX_BUF_SIZE 1024int main(void){int fd;int wd;char buffer[1024];char * offset = NULL;struct inotify_event * event;int len, tmp_len;char strbuf[16];int i = 0;fd = inotify_init();if (fd < 0) {printf("Fail to initialize inotify.\n");exit(-1);}for (i=0; imask & IN_ISDIR) {memcpy(strbuf, "Direcotory", 11);}else {memcpy(strbuf, "File", 5);}printf("Object type: %s\n", strbuf);for (i=0; iwd != wd_array[i].wd) continue;printf("Object name: %s\n", wd_array[i].name);break;}printf("Event mask: %08X\n", event->mask);for (i=0; imask & (1

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/dianzi/90644.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部