文件系统抽象层VFS

文件系统抽象层是把不同文件系统的对外共性接口提取出来,形成一个函数指针数组,这样,通用文件系统访问接口层只需访问文件系统抽象层,而不需关心具体文件系统的实现细节和接口。

file&dir接口

file&dir 接口层定义了进程在内核中直接访问的文件相关信息,这定义在 file 数据结构中,具体描述如下:

// kern/fs/file.h
struct file {
    enum {
        FD_NONE, FD_INIT, FD_OPENED, FD_CLOSED,
    } status;                         //访问文件的执行状态
    bool readable;                    //文件是否可读
    bool writable;                    //文件是否可写
    int fd;                           //文件在filemap中的索引值
    off_t pos;                        //访问文件的当前位置
    struct inode *node;               //该文件对应的内存inode指针
    int open_count;                   //打开此文件的次数
};

而在 kern/process/proc.h中的 proc_struct 结构中加入了描述了进程访问文件的数据接口 files_struct,其数据结构定义如下:

// kern/fs/fs.h
struct files_struct {
    struct inode *pwd;                //进程当前执行目录的内存inode指针
    struct file *fd_array;            //进程打开文件的数组
    atomic_t files_count;             //访问此文件的线程个数
    semaphore_t files_sem;            //确保对进程控制块中fs_struct的互斥访问
};

当创建一个进程后,该进程的 files_struct 将会被初始化或复制父进程的 files_struct。当用户进程打开一个文件时,将从 fd_array 数组中取得一个空闲 file 项,然后会把此 file 的成员变量 node 指针指向一个代表此文件的 inode 的起始地址。

inode接口

index node 是位于内存的索引节点,它是 VFS 结构中的重要数据结构,因为它实际负责把不同文件系统的特定索引节点信息(甚至不能算是一个索引节点)统一封装起来,避免了进程直接访问具体文件系统。其定义如下:

在 inode 中,有一成员变量为 in_ops,这是对此 inode 的操作函数指针列表,其数据结构定义如下:

参照上面对 SFS 中的索引节点操作函数的说明,可以看出 inode_ops 是对常规文件、目录、设备文件所有操作的一个抽象函数表示。对于某一具体的文件系统中的文件或目录,只需实现相关的函数,就可以被用户进程访问具体的文件了,且用户进程无需了解具体文件系统的实现细节。

open系统调用的执行过程

下面我们通过打开文件的系统调用open()的执行过程, 看看文件系统的不同层次是如何交互的。

首先,经过syscall.c的处理之后,进入内核态,执行sysfile_open()函数

可以看到,sysfile_open 把路径复制了一份,然后调用了file_openfile_open调用了vfs_open, 使用了VFS的接口。

vfs_open是一个比较复杂的函数,这里我们使用的打开文件的flags, 基本是参照linux,如果希望详细了解,可以阅读linux manual: open

我们看看vfs_look_up的实现

我们注意到,这个流程中,有大量以vop开头的函数,它们都通过一些宏和函数的转发,最后变成对inode结构体里的inode_ops结构体的“成员函数”(实际上是函数指针)的调用。对于SFS文件系统的inode来说,会变成对sfs文件系统的具体操作。sfs的这些具体接口的实现较为繁琐,可以在kern/fs/sfs/sfs_inode.c具体查看。我们的练习要求在kern/fs/sfs/sfs_io.c填写一个函数。

最后更新于

这有帮助吗?