file_operations流程跟踪
术语
描述符:其实就是结构体
在linux可以把设备看作文件并提供了和文件一样的统一的访问接口,相信大家已经有了一
点的了解,其底层对设备的不同操作主要是由file_operations描述符来控制,其封装了各
种设备的操作方法,如:open/read/write/ioctl等等。
linux中每个文件或目录都对一个名为inode的结构体,其中有一个字段i_fop就是存储文件
的操作方法file_operations实例对象。以下我们将对文件的file_operations如何赋值给
inode->i_fop进行一个简单的跟踪。
linux中,支持很多的文件系统,每个文件系统使用之前都必须要先注册,其注册的过程大
体一致,以下我们将以ext3文件系统为例跟踪file_operations的注册过程。
在文件系统的初始化阶段调用register_filesystem(&ext3_fs_type)函数将以下结构:
static struct file_system_type ext3_fs_type = {
.owner = THIS_MODULE,
.name = "ext3",
.get_sb = ext3_get_sb,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
注册到全局链表file_systems(fs/filesystems.c)中。
其中函数指针get_sb在超级块全局链表super_blocks(fs/super.c)中查找文件系统对应的超级
块描述符并返回,如果没有则创建新的描述符。
当get_sb函数指针被调用,触发ext3_fill_super(fs/ext3/super.c其为get_sb参数之一的函数
指针)函数调用ext3_iget返回超级块所对应的文件系统的根目录的inode,并根据inode->i_mode
来判断文件类型赋予相应的操作,源代码(fs/ext3/inode.c)如下:
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext3_file_inode_operations;
inode->i_fop = &ext3_file_operations;
ext3_set_aops(inode);
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext3_dir_inode_operations;
inode->i_fop = &ext3_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
if (ext3_inode_is_fast_symlink(inode)) {
inode->i_op = &ext3_fast_symlink_inode_operations;
nd_terminate_link(ei->i_data, inode->i_size,
sizeof(ei->i_data) - 1);
} else {
inode->i_op = &ext3_symlink_inode_operations;
ext3_set_aops(inode);
}
} else {
inode->i_op = &ext3_special_inode_operations;
if (raw_inode->i_block[0])
init_special_inode(inode, inode->i_mode,
old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
else
init_special_inode(inode, inode->i_mode,
new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
}
在此,我主要讲解对init_special_inode的跟踪,其他函数希望感兴趣的读者自己跟踪。
在对 init_special_inode进行跟踪之前先来说明一下linux的文件路径名查找,当要对
某个索引节点进行处理时,代码首先检查路径名中与第一个名字匹配的目录项,以获得
相应的索引节点。然后,从磁盘读出包含那个索引节点的目录文件,并检查与第二个名
字匹配的目录项,以获得相应的索引节点。对于包含在路径中的每个名字,这个过程反
复执行。那么,当要创建新文件(创建新inode)的时,系统调用其父inode的方法来创建
子inode的。
顾名思义,init_special_inode函数的作用就是初始化特殊的inode,先不多说,看下
面的源码(fs/inode.c):
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) {
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
} else if (S_ISFIFO(mode))
inode->i_fop = &def_fifo_fops;
else if (S_ISSOCK(mode))
inode->i_fop = &bad_sock_fops;
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
" inode %s:%lu/n", mode, inode->i_sb->s_id,
inode->i_ino);
}
根据上面代码可以得出,init_special_inode对字符设备文件、块设备文件、管道文件、网
络设备文件进行处理,分别赋予inode中的file_operations变量def_chr_fops/def_blk_fops/
def_fifo_fops/bad_sock_fops。
def_chr_fops,fs/char_dev.c文件中的全局变量,源码如下:
const struct file_operations def_chr_fops = {
.open = chrdev_open,
};
chrdev_open,定义在同文件下,其调用了kobj_lookup函数在cdev_map链表中查找对应的
struct kobj_map对象。
现在我们反过来看驱动,在fs/char_dev.c文件中维护了一个struct kobj_map类型的链表cdev_map,
当注册字符设备时file_operations对象被添加到cdev描述符中,添加设备的时候调用kobj_map(
drivers/base/map.c)其最后一个参数为void×类型,传递cdev对象给kobj_map对象。
以上只是一个简单的对file_operations描述符的跟踪,基本上描述了字符设备的这一过程,由于
时间的关系以上的细节描述得不是很详细,而且也没有完全跟踪,希望有兴趣的读者能够自己跟踪。
(注:以上文章仅供参考。由于水平有限,如有问题还请谅解。
基于2.6.32的内核)。