notify_change()函数的作用是注册一个通知器,当文件的属性改变后,用来通知文件系统。改变的属性放在attr结构体中,函数首先会对传入的参数attr进行设置,使其对当前文件系统可用。struct iattr的定义见文件linux-3.19.3/include/linux/fs.h:
struct iattr {
unsigned int ia_valid; /*检验是否有权限被修改*/
umode_t ia_mode; /*该节点的模式*/
uid_t ia_uid; /*所有者标识符*/
gid_t ia_gid; /*组标识符*/
loff_t ia_size; /*文件的字节数*/
struct timespec ia_atime; /*上次访问文件的时间*/
struct timespec ia_mtime; /*上次写文件的时间*/
struct timespec ia_ctime; /*上次修改索引节点的时间*/
struct file *ia_file;
};
其中的字段ia_valid的值可以是下面的宏,或是几个宏进行“或”操作,定义见文件linux-3.19.3/include/linux/fs.h。
#define ATTR_MODE (1<<0)
#define ATTR_UID (1<<1)
#define ATTR_GID (1<<2)
#define ATTR_SIZE (1<<3)
#define ATTR_ATIME (1<<4)
#define ATTR_MTIME (1<<5)
#define ATTR_CTIME (1<<6)
#define ATTR_ATIME_SET (1<<7)
#define ATTR_MTIME_SET (1<<8)
#define ATTR_FORCE (1<<9)
#define ATTR_ATTR_FLAG (1<<10)
#define ATTR_KILL_SUID (1<<11)
#define ATTR_KILL_SGID (1<<12)
#define ATTR_FILE (1<<13)
#define ATTR_KILL_PRIV (1<<14)
#define ATTR_OPEN (1<<15)
#define ATTR_TIMES_SET (1<<16)
notify_change文件包含
#include <linux/fs.h>
notify_change函数定义
在内核源码中的位置:linux-3.19.3/fs/attr.c
函数定义格式:
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
notify_change输入参数说明
dentry
:发生改变后的inode结构体所在的目录dentry结构体变量,其定义及详细说明参考极客笔记中d_alloc ()函数的参数说明部分。attr
:包含需要改变inode结构体的各个字段修改信息的iattr结构体。其字段包括所有者标识符、组标识符、文件的字节数、上次访问文件的时间、上次写文件的时间、上次修改索引节点的时间等。delegated_inode
:struct inode类型结构体变量的指针,如果inode的属性被更改,新的信息将会保存在delegated_inode中,其定义及详细说明参考极客笔记中d_find_alias()函数的参数说明部分。
notify_change返回参数说明
notify_change()
函数的返回结果是int型的变量,可能的取值是0或-1,若返回0,则表示已经给文件系统成功发送了提示信息;返回-1,则说明发送的提示信息没有成功。其中,-1表示返回值的错误标志是-EPERM,而EPERM宏在linux-3.19.3/include/asm-generic/errno-base.h文件中被定义,值为1,含义为操作不被允许。
notify_change实例解析
编写测试文件:notify_change.c
头文件声明如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/path.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
定义变量:
struct iattr attr=
{
. ia_atime.tv_sec = 0
};
模块初始化函数:
int notify_change_init(void)
{
struct dentry *dentry;
struct inode * node = (struct inode*)(kmalloc(sizeof(struct inode), GFP_KERNEL));
dentry = current->fs->pwd.dentry; //获取当前文件的入口目录
printk("attr.ia_atime.tv_sec = %ld\n", attr.ia_atime.tv_sec); //显示属性的时间值
int res = notify_change(dentry, &attr, &node); //改变当文件的属性
printk("The returned value of \"notify_change\" is %d.\n", res);
//显示函数notify_change()的返回结果
printk("attr.ia_atime.tv_sec = %ld\n", attr.ia_atime.tv_sec); //显示属性的时间值
kfree(node);
return 0;
}
模块退出函数:
void notify_change_exit(void)
{
printk("Goodbye notify_change\n");
}
模块初始化及退出函数调用:
module_init(notify_change_init);
module_exit(notify_change_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod notify_change.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
预先设置iattr结构体的访问时间属性为0,然后通过notify_change()函数注册属性改变通知器,再次显示iattr结构体的访问时间属性,notify_change()函数的返回值为0,说明通知器注册成功,同时,iattr内部的字段值也发生了变化,时间字段值变为与当前系统同步。