虚拟文件系统
虚拟文件系统
虚拟文件系统(VFS)作为内核的子系统,为用户空间程序提供了文件和文件系统的相关接口。总的来说,其作用就是提供一套标准化的通用接口给上层使用,而下层可以是不同的文件系统,VFS可以看作是一个抽象的中间层。
文件系统抽象层
VFS抽象层之所以能够衔接各种各样的文件系统,是因为它定义了所有文件系统都支持的、基本的、概念上的接口和数据结构
。同时,实际的文件系统也将自身的操作在形式上与VFS的定义保持一致。通俗点说就是VFS提供基本的接口和数据结构,实际文件系统去实现具体的细节。所以在VFS和内核的其他部分来看,所有文件系统都是相同的(比如说,它们都支持文件和目录的概念,都有打开、读取、关闭的操作)。
例如,用户空间对写文件的操作,如下:
Unix文件系统
Unix使用了四种和文件系统相关的抽象概念:文件、目录项、索引节点和安装点(mount point)。
Unix中文件通过目录组织起来,目录可以容纳多个文件,目录也可以包含其他目录。在Unix中,目录也属于普通文件,它列出了包含在其中的所有文件,可以对目录执行和文件相同的操作。
inode:文件的相关信息和文件本身内容这两个概念在Unix中被区分开了。文件的相关信息,例如访问权限、大小、创建时间等,被称为文件的元数据,被存储在单独的数据结构中,该结构被称为索引节点(inode)。
超级块:文件系统控制信息存放在超级块中,超级块是一种包含文件系统信息的数据结构。
VFS对象
VFS采用面向对象的设计思路,使用一组数据结构来表示通用的文件对象。这些数据结构类似于对象(因为使用c语言实现,但是c语言中没有对象这个概念,因此用结构体表示),其中包含了数据以及操作这些数据的函数指针,而这些操作函数由具体的文件系统实现
。
VFS中四个主要对象
-
超级块对象,代表一个具体的已安装文件系统
该对象用于存储特定文件系统的控制信息。各种文件系统都必须实现超级块对象。在文件系统安装时,文件系统会调用相关函数从磁盘中读取超级块信息,并将其填充到内存的超级块对象中。 -
索引节点对象,具体的文件
包括了文件或目录的全部信息。如果实际的文件系统中没有索引节点这一概念(例如有些文件系统将文件信息和文件内容放在一起),文件系统也必须从中提供这些信息初始化到内存中的索引节点来供VFS使用。
一个索引节点代表文件系统中的一个文件,索引节点只有当文件被访问是才会在内存中被创建。 -
目录项对象,路径的组成部分
VFS把目录也当作文件对待,但是VFS经常需要执行目录相关的操作,为了方便,引入了目录项的概念。在路径中,每一个部分都是目录项对象,VFS在执行目录操作时,会现场创建目录项对象。
注意,目录项没有对应的磁盘结构
,而是VFS根据路径名现场创建它(一个目录项对应一个索引节点)。目录项涉及到目录项缓存,是一个比较关键的点,需要查资料掌握。 -
文件对象,由进程打开的文件
文件对象是已打开文件在内存中的表示,由系统调用open创建,close系统调用撤销。文件对象中包含了访问文件时的一些信息,例如,文件的访问模式、当前的偏移等。
注意,VFS采用的是面向对象的思想,各种不同类型文件系统,都需要实现VFS提供的回调函数来满足VFS需要实现的目的(每种VFS对象中都有一个操作函数表)
。例如,上述的四个对象结构中都包含了大量的操作函数(需要实际文件系统实现)。
和文件系统相关的数据结构
file_systerm_type
用来描述特定的文件系统类型
,因为linux支持众多文件系统,因此内核必须由一个特殊的结构来描述每种文件系统的功能和行为(也就是说,每种文件系统都必须实现该结构)。具体结构如下:
vfsmount
当文件系统被安装时,会有一个vfsmount结构体在安装点被创建。该结构体用来代表文件系统的安装点
。具体结构如下:
和进程相关的数据结构
系统中每个进程都有自己的一组打开的文件,像根文件系统、当前工作目录、安装点等
。有三个数据结构将VFS层和系统的进程紧密联系在一起。它们分别是:file_struct、fs_struct和namespace结构体。
file_struct
该结构体定义在<linux/fdtable.h>文件中。由进程描述符中的files字段指向,所有与单个进程相关的文件信息(打开的文件以及文件描述符)都包含在其中,其结构如下:
fs_struct
该结构体由进程描述符的fs域指向,它包含当前进程的工作目录
和根目录
。定义在文件<linux/fs_struct.h>中,其结构如下:
mmt_namespace
该结构体定义在文件<linux/mmt_namespace.h>中,由进程描述符中的mmt_namespace域指向。2.4内核版本以后,单进程命名空间被加入到内核中,它使得每一个进程在系统中都看到唯一安装的文件系统
(不仅是唯一的根目录,而且是唯一的文件系统层次结构)。其结构如下:
对多数进程来说,他们使用的file_struct和fs_struct结构都是唯一的,但是对于那些使用CLONE_FILE或CLONE_FS创建的进程,父子进程会共享这两个结构,并通过引入计数来控制。
注:声明一下,关于linux内核分析我都是概要的记录一下(记录自己认为每个模块中重要的地方),其作用是在心中有一个大概的轮廓,具体的细节还需到各个模块代码中深入研究。