Linux-虚拟文件系统

虚拟文件系统(VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口。程序可以利用标准的Unix系统调用不同的文件系统,甚至是不同介质上的文件系统。

文件系统抽象层

之所以可以使用这种通用接口对所有类型的文件系统进行操作,是因为内核在它的底层文件系统接口上建立了一个抽象层。它定义了所有文件系统都支持的、基本的、概念上的接口和数据结构。

Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点和安装点。

安装点(Mount Point)

在Unix系统中,文件系统被安装在一个特定的安装点上,该安装点在全局层次结构中被称作命名空间,所有的已安装文件系统都作为根文件系统树的枝叶出现在系统中。

文件

文件是简单的面向字节流的有序字节串。

目录项

文件通过目录组织起来。目录条目统称为目录项。在Unix中,目录属于普通文件,它列出包含在其中的所有文件。

索引节点

Unix系统将文件的相关信息和文件本身这两个概念加以区分,例如访问控制权限、大小、拥有者、创建时间等信息。文件相关信息,被存储在一个单独的数据结构中,该结构被称为索引节点。

超级块

超级块是一种包含文件系统信息的数据结构。

VFS对象及其数据结构

VFS采用的是面向对象的设计思路,使用一组数据结构来代表通用文件对象。

VFS中有四个主要的对象类型

  1. 超级块对象:代表一个具体的已安装文件系统
  2. 索引节点对象:代表一个具体文件
  3. 目录项对象:代表一个目录项,是路径的一个组成部分
  4. 文件对象:代表由进程打开的文件

因为VFS将目录作为一个文件来处理,所以不存在目录对象。

超级块对象

各种文件系统都必须实现超级块对象,该对象用于存储特定文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块或文件系统控制块。对于并非基于磁盘的文件系统(如基于内存的文件系统,比如sysfs),它们会在使用现场创建超级块并将其保存到内存中。

1
2
3
4
struct super_block {
unsigned long long s_maxbytes;//文件大小上限
struct file_system_type s_type;//文件系统类型
}

索引节点对象

索引节点对象包含了内核在操作文件或目录时需要的全部信息。对于Unix风格的文件系统来说,这些信息可以从磁盘索引节点直接读入。如果一个文件系统没有索引节点,那么,不管这些相关信息在磁盘上是怎么存放的,文件系统都必须从中提取信息。没有索引节点的文件系统通常将文件的描述信息作为文件的一部分来存放。这些文件系统与Unix风格的文件系统不同,没有将数据与控制信息分开存放。有些现代文件系统使用数据库来存储文件的数据。不管哪种情况、采用哪种方式,索引节点对象必须在内存中创建,以便于文件系统使用。

一个索引节点代表文件系统中(但是索引节点仅当文件被访问时,才在内存中创建)的一个文件,它也可以是设备或管道这样的特殊文件。

1
2
3
4
5
6
7
8
struct inode {
unsigned long i_ino;//节点号
atomic_t i_count;//引用计数
loff_t i_size;//以字节为单位的文件大小
struct address_space *i_mapping;//相关的地址映射
struct address_space i_data;//设备地址映射
struct dquot *i_dquot[MAXQUOTAS];//索引节点的磁盘限额
}

目录项对象

为了方便查找操作,VFS引入了目录项的概念。每个dentry代表路径中的一个特定部分。在路径中(包括普通文件在内),每一个部分都是目录项对象。

1
2
3
4
5
6
7
// <linux/dcache.h>

struct dentry {
struct dentry *d_parent;//父目录的目录项对象
struct qstr d_name;//目录项名称
struct inode *d_inode;//相关联的索引节点
}

文件对象

文件对象表示进程已打开的文件。文件对象是已打开的文件在内存中的表示。因为多个进程可以同时打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象。文件对象仅仅在进程观点上代表已打开文件,它反过来指向目录项对象。

1
2
3
4

struct file {
struct path f_path;//包含目录项
}