2.4.5 用户空间inotify机制
1.inotify机制用户空间接口
在用户空间,inotify机制提供了inotify_init、inotify_add_watch和inotify_rm_watch3个系统调用,还提供了文件系统操作。这样,应用程序可以使用inotify机制进行文件系统监视处理。
应用程序调用inotify机制的接口函数的方法列出如下:
int fd = inotify_init (); //创建inotify机制文件描述符 //添加一个watch,path 是被监视的目标的路径,mask 是事件掩码,wd是watch描述符 int wd = inotify_add_watch (fd, path, mask); //buf是一个inotify_event 结构的数组指针,BUF_LEN指定要读取的总长度,buf不小于 BUF_LEN size_t len = read (fd, buf, BUF_LEN); //读取多个事件,文件描述符 fd 上使用 select() 或poll() int ret = inotify_rm_watch (fd, wd); //删除一个 watch close(fd); |
2.应用程序使用inotify机制样例
以下的样例程序监视几个文件或目录的所有文件系统事件,并打印出事件说明。应用程序使用inotify机制的样例程序列出如下:
$cat inotify_usespace.c #include |
编译应用程序的方法如下:
$gcc -o inotify_userspace -I . inotify_usersapce.c |
在一个虚拟终端上运行应用程序inotify_userspace,在另一个虚拟终端执行命令 cat ./tmp_file。程序的输出列出如下:
Some event happens, len = 48. Object type: File Object name: ./tmp_file Event mask: 00000020 Event: File was opened Object type: File Object name: ./tmp_file Event mask: 00000001 Event: File was accessed Object type: File Object name: ./tmp_file Event mask: 00000010 Event: Unwrittable file closed |
3.用户空间inotify机制的数据结构
用户空间inotify机制是inotify机制的扩展,因此,它的数据结构从inotify机制的数据结构继承。
结构inotify_user_watch是从基类结构inotify_watch派生的类结构,它在继承基类的基础上加入了成员inotify_device。其列出如下(linux26/fs/inotify_user.c中):
struct inotify_user_watch {
struct inotify_device*dev;/*可以看作设备,含有链表,用于将事件传递回用户空间*/
struct inotify_watchwdata;/*inotify机制的watch(监视实例)*/
};
|
结构inotify_device是从基类结构inotify_handle派生的类结构,代表了监视处理实例。它含有事件队列events,用于存储发生在节点的inotify机制事件,应用程序可以通过伪文件系统inotifyfs的读操作函数从这个事件队列中读取事件。为了协调事件的读取和写入,结构inotify_device还添加了等待队列成员wq,用于同步事件的读取和写入的操作。
结构inotify_device列出如下:
struct inotify_device {
wait_queue_head_t wq;/* i/o 的等待队列*/
struct mutexev_mutex;/* 用于保护事件队列*/
struct mutexup_mutex;/*用于同步watch更新*/
struct list_head events;/*排队事件的链表*/
atomic_tcount;/*引用计数 */
struct user_struct*user;/*打开这个设备的用户*/
struct inotify_handle *ih;/*监视处理实例 */
unsigned intqueue_size;/*队列的大小 (bytes) */
unsigned intevent_count;/* 挂起事件的数量*/
unsigned intmax_events;/* 最大事件数*/
};
|
4.用户空间inotify机制的系统调用
内核提供了系统调用sys_inotify_init、sys_inotify_add_watch和sys_inotify_rm_watch支持用户空间的inotify机制。
1)系统调用sys_inotify_init
系统调用sys_inotify_init调用了inotify_init初始监视处理实例,监视处理实例含有操作函数集inotify_user_ops,其列出如下(在linux26/fs/inodify_user.c中):
static const struct inotify_operations inotify_user_ops = {
.handle_event= inotify_dev_queue_event,
.destroy_watch= free_inotify_user_watch,
};
|
当文件系统被改变时,inotify机制的hook函数会从节点的watch中得到监视处理实例,再找到操作监视处理实例的函数集inotify_user_ops,并调用其中的函数inotify_dev_queue_event处理inotify机制的事件。
函数inotify_dev_queue_event将事件写入到结构inotify_device的事件队列中,并唤醒伪文件系统inotifyfs的读操作进程。由读操作将事件传递给用户空间的应用程序。
2)系统调用sys_inotify_add_watch
系统调用sys_inotify_add_watch查找文件路径所对应的节点,在节点的watch链表中查找与监视处理实例匹配的watch,如果没有找到就创建watch,并将watch加到节点的watch链表中。
3)系统调用sys_inotify_rm_watch
系统调用sys_inotify_rm_watch从监视处理实例的watch链表中删除watch。
5.用户空间inotify机制的伪文件系统inotifyfs
模块初始化函数inotify_user_setup注册了伪文件系统inotifyfs,其列出如下:
static int __init inotify_user_setup(void)
{
int ret;
ret = register_filesystem(&inotify_fs_type);//注册文件系统
if (unlikely(ret))
panic("inotify: register_filesystem returned %d!\n", ret);
inotify_mnt = kern_mount(&inotify_fs_type); //挂接文件系统
if (IS_ERR(inotify_mnt))
panic("inotify: kern_mount ret %ld!\n", PTR_ERR(inotify_mnt));
inotify_max_queued_events = 16384;
inotify_max_user_instances = 128;
inotify_max_user_watches = 8192;
watch_cachep = kmem_cache_create("inotify_watch_cache",
sizeof(struct inotify_user_watch),
0, SLAB_PANIC, NULL, NULL);
event_cachep = kmem_cache_create("inotify_event_cache",
sizeof(struct inotify_kernel_event),
0, SLAB_PANIC, NULL, NULL);
return 0;
}
|
文件系统类型结构实例列出如下(在linux26/fs/inotify_user.c中):
static struct file_system_type inotify_fs_type = {
.name = "inotifyfs",//文件系统类型名
.get_sb = inotify_get_sb, //得到文件系统超级块
.kill_sb = kill_anon_super, //删除超级块
};
|
函数inotify_get_sb创建并初始化伪文件系统超级块,其列出如下:
static int inotify_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA, mnt); //文件系统模数为0xBAD1DEA
}
|
当应用程序调用函数sys_inotify_init初始化监视处理实例并创建inotify机制文件描述符时,监视处理实例绑定了操作函数集inotify_user_ops,文件描述符绑定了文件操作函数集inotify_fops。
文件操作函数集inotify_fops定义了伪文件系统inotifyfs的文件操作函数,其列出如下(在linux26/fs/inotify_user.c中):
.poll = inotify_poll, //从文件等待接收数据 .read = inotify_read, //从文件读取数据 .release = inotify_release, //释放描述符的各种结构实例所占空间 .unlocked_ioctl = inotify_ioctl, .compat_ioctl= inotify_ioctl, }; |
函数inotify_read从事件队列中读出事件到用户空间的缓冲区buf中。当事件队列为空时,当前进程便进入等待状态。当事件队列不为空时,当前进程被唤醒,它从事件队列中取出事件,将事件和事件名拷贝到用户空间。
函数inotify_read列出如下:
static ssize_t inotify_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
size_t event_size = sizeof (struct inotify_event);
struct inotify_device *dev;
char __user *start;
int ret;
DEFINE_WAIT(wait); //声明等待队列wait
start = buf;
dev = file->private_data;
while (1) {
int events;
//将dev->wq加入等待队列wait,设置当前进程状态为TASK_INTERRUPTIBLE状态
prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE);
mutex_lock(&dev->ev_mutex);
events = !list_empty(&dev->events); //如果事件队列不为空
mutex_unlock(&dev->ev_mutex);
if (events) {//如果有事件存在,中断循环
ret = 0;
break;
}
//运行到这里,说明事件队列中不存在事件
if (file->f_flags & O_NONBLOCK) { //如果是非阻塞标识,则返回
ret = -EAGAIN;
break;
}
if (signal_pending(current)) { //如果当前进程是挂起状态,则中断循环
ret = -EINTR;
break;
}
schedule();//调度
}
finish_wait(&dev->wq, &wait); //从等待中唤醒
if (ret)
return ret;
mutex_lock(&dev->ev_mutex);
while (1) {
struct inotify_kernel_event *kevent;
ret = buf - start;
if (list_empty(&dev->events)) //如果事件队列为空,跳出循环
break;
kevent = inotify_dev_get_event(dev); //得到事件
if (event_size + kevent->event.len > count)
break;
if (copy_to_user(buf, &kevent->event, event_size)) {
//将事件拷贝到用户空间的缓冲区buf中
ret = -EFAULT;
break;
}
buf += event_size;
count -= event_size;
if (kevent->name) {//将事件名拷贝到用户空间的缓冲区buf中
if (copy_to_user(buf, kevent->name, kevent->event.len)){
ret = -EFAULT;
break;
}
buf += kevent->event.len;
count -= kevent->event.len;
}
remove_kevent(dev, kevent);
}
mutex_unlock(&dev->ev_mutex);
return ret;
}
|
| 回书目 上一节 下一节 |
|
· 第六章 你能帮我吗?.. · Linux笔试面试题选摘测.. · 08年5月软考网管上午真.. · 性能测试从零开始 目录 · 08年5月软考网工上午真.. · 上周拒绝服务攻击(DDo.. |
· 08年5月各大网上书店及.. · 2008年5月24日软考试题.. · 软件设计师专家临考模.. · 上周网络管理员专家自.. · 网络工程师自测获奖名.. · 08年4月各大网上书店及.. |
|
||||
| · NAC安全访问控制 · 网络布线测试仪器 · Windows Server 2008专.. · Windows远程桌面应用 · 网络故障排除宝典 · 运营商封堵ADSL共享 中.. · 解析35岁技术人的价值.. · 世纪枭雄比尔盖茨的王.. |
· 主流品牌防火墙配置 · ASP.NET开发教程 · 超级计算机TOP500专题 · Vista SP1对决XP SP3 · SQL Server 2008/2005.. · 程序员如何成长? · C#技术开发指南 · 虚拟化技术还有点“虚” |
|||
|
||||
| · SOA 面向服务架构 · SQL Server 2008/2005.. · Apache技术专题 · 三层交换技术专题 · SQL Server入门到精通 · Windows远程桌面应用 · C#技术开发指南 · Apache技术专题 |
· Windows集群服务应用 · C#技术开发指南 · 国际文档格式标准开战 · 路由器设置与口令恢复 · Linux 集群技术专题 · PHP开发应用手册 · SOA 面向服务架构 · 企业数据恢复指南 |
|||
|
||||
| · SQL Server入门到精通 · SQL Server 2008/2005.. · SOA 面向服务架构 · Apache技术专题 · C#技术开发指南 · 三层交换技术专题 · Apache技术专题 · C#技术开发指南 |
· Windows远程桌面应用 · 企业数据恢复指南 · Windows集群服务应用 · 路由器设置与口令恢复 · Linux 集群技术专题 · SOA 面向服务架构 · 了解统一威胁管理(UTM).. · 反垃圾邮件技术应用 |
|||