我们知道linux系统中文件有很多种,包括普通文件,目录文件,设备文件,管道文件,套接字文件等.文件在内核中用file结构体表示,file对象中有个重要成员 f_op指针,它指向file_operations,该结构体定义了一系列文件操作的函数指针集合,例如open,read,write,ioctl,mmap等.当对文件进行操作时,最终是调用对应的函数指针进行操作.
linux中支持很多种文件系统,每个文件系统使用之前都必须要先注册才能使用,文件系统类型用结构体file_system_type表示,注册文件系统使用register_filesystem(struct file_system_type * fs),它的作用是将文件系统类型添加到全局链表file_systems中.下面我以linux主流磁盘文件系统类型ext4的注册流程进行分析.
//下面是定义一个ext4文件系统类型
static struct file_system_type ext4_fs_type = {
.owner = THIS_MODULE,
.name = "ext4",
.mount = ext4_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
在用户空间执行mount系统调用进行挂载文件系统时会调用ext4_mount(),基本流程为:do_mount()->do_new_mount()->do_kern_mount()->vfs_kern_mount()->mount_fs()->ext4_fs_type.mount()->ext4_mount(),感兴趣的读者请自行分析.
static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data)
{
return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super);
}
mount_bdev函数原型声明如下:
struct dentry *mount_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int)) {
}
注意上面函数mount_bdev的最后一个参数ext4_fill_super,它是一个函数指针,指向函数ext4_fill_super.
mount_bdev中会调用ext4_fill_super()函数,代码片段如下:
struct dentry *mount_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int))
{
.........
s->s_flags = flags | MS_NOSEC;
s->s_mode = mode;
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
sb_set_blocksize(s, block_size(bdev));
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error) {
deactivate_locked_super(s);
goto error;
}
s->s_flags |= MS_ACTIVE;
bdev->bd_super = s;
}
下面看ext4_fill_super的执行流程代码片段:
static int ext4_fill_super(struct super_block *sb, void *data, int silent) {
.....
/*
* The jbd2_journal_load will have done any necessary log recovery,
* so we can safely mount the rest of the filesystem now.
*/
root = ext4_iget(sb, EXT4_ROOT_INO);
if (IS_ERR(root)) {
ext