您的位置:首页 > 其它

向下之旅(十七):虚拟文件系统(一)

2016-03-28 15:17 162 查看
  虚拟文件系统(或称虚拟文件交换,更常见的简称VFS)作为内核子系统,为用户空间程序提供了文件系统相关的接口。系统中所有文件系统不但依赖VFS共存,而且也依靠VFS系统协同工作。通过虚拟文件系统,程序可以利用标准的UNIX文件系统调用对不同介质上的不同文件系统进行读写操作。模式图如下:



  通用文件系统接口

  VFS可以让用户直接可以使用open()、read()和write()这样的系统调用而无需考虑具体文件系统和实际物理介质。系统调用可以在这些不同的文件系统和介质之间执行——我们可以使用标准的系统调用从一个文件系统拷贝或移动数据到另一个文件系统。

  文件系统抽象层

  之所以可以使用统一接口操作不同的文件系统,是因为内核在它的底层文件系统接口上建立了一个抽象层。该抽象层使Linux能够支持各种文件系统,即便是它们在功能和行为上存在很大差别。

  VFS抽象层之所以能够衔接各种文件系统,是因为它定义了所有文件系统都支持的基本的、概念上的接口和数据结构。

  其实在内核中,除了文件系统本真外,其他部分并不需要了解文件系统的内部细节。比如一个简单的用户空间程序执行如下操作:

  write(f,&buf,len);

  改代码将&buf指针指向的、长度为len自己的数据写入文件描述符f对应的文件的当前位置。这个用户调用首先被一个通用系统调用sys_write()处理,sys_write()函数要找到f所在的文件系统实际给出的是哪个写操作,然后在执行该操作。实际文件系统的写方法是文件系统实现的一部分,数据最终通过该操作写入介质(或执行这个文件系统想要完成的写动作)。一方面,系统调用是通过VFS接口,提供给用户空间的前端,另一方面,系统调用是具体文件系统的后端,处理实现细节。如图所示:

  


  Unix文件系统

  Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点和安装点。从本质上讲文件系统是特殊的数据分层存储结构。它包含文件、目录和相关的控制信息。文件系统的通用操作包含创建、删除和安装等等。在Unix中,文件系统被安装在一个特定的安装点上,该安装点在全局层次结构中被称作命名空间,所有的已安装文件系统都作为根文件系统树的枝叶出现在系统上。

  文件通过目录组织起来,因为目录也可以包含子目录,所以目录可以层层嵌套,形成文件路径。由于VFS把目录当做文件对待,所以可以对目录执行和文件相同的操作。

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

  所有这些信息都和文件系统的控制信息密切交融,文件系统的控制信息存储在超级块中,超级块是一种包含文件系统信息的数据结构。有时,把这些收集起来的信息称为文件系统数据元,它集单独文件信息和文件系统的信息于一身。

  VFS对象及其数据结构

  VFS采用面向对象的设计思路,使用一族数据结构来代表通用文件对象。因内核纯粹用C代码实现,没有直接利用面向对象的语义,所以内核中的数据结构都使用C结构体实现,但这些结构体包含数据的同时也包含操作这些数据的函数指针,其中的操作函数由具体文件系统实现。

  VFS中有四个主要的对象类型,分别为:

  1.超级块对象,它代表一个已安装文件系统。

  2.索引节点对象,它代表一个文件。

  3.目录项对象,它代表一个目录项,是路径的一个组成部分。

  4.文件对象,它代表由进程打开的文件。

  每个主要对象中都包含一个操作对象,这些操作对象描述了内核针对主要对象可以使用的方法。最主要的几种操作对象如下:

  1.super_operations对象,其中包括内核针对特定文件系统所能调用的方法,比如read_inode()和sync_fs()等方法。

  2.inode_operations对象,其中包括内核针对特定文件所能调用的方法,比如create()和link()等方法。

  3.dentry_operations对象,其中包换内核针对特定目录所能调用的方法,比如d_compare()和d_delete()等方法。

  4.file对象,其中包括进程针对已打开文件所能调用的方法,比如read()和write()等方法。

  操作对象作为一个指针结构体被实现,此结构体中包含指向操作其父对象的函数指针。对于其中许多方法来说,可以继承使用VFS提供的通用函数,若通用函数提供的基本功能无法满足需要,那么就必须使用实际文件系统的独有方法填充这些函数指针,使其指向文件系统实例。

  再次提醒,我们这里所说的对象就是指结构体——而不是像C++或java那样的真正的对象数据类型。但是这些结构体的确代表的是一个对象,含有相关的数据和对这些数据的操作,所以说它们就是对象。

  超级块对象

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

  


  超级块对象通过alloc_super()函数创建并初始化。在文件系统安装时,内核会调用该函数以便从磁盘读取文件系统超级块,并且将其信息填充到内存中的超级块对象中。

  超级块操作

  超级块对象中最重要的一个域是s_op,它指向超级块的操作函数表。超级块操作函数表由super_operations结构体表示,结构如下:



  该结构体中的每一项都是一个指向超级块操作函数的指针,超级块操作函数执行文件系统和索引节点的底层操作。

  当文件系统需要对其超级块执行操作时,首先要在超级块对象寻找需要的操作方法。比如,如果一个文件系统要写自己的超级块,需调用:

  sb->s_op->write_super(sb);

  这里的sb是指向文件系统超级块的指针,沿着该指针进入超级块操作函数表,并从表中取得希望得到的write_super()函数,该函数执行写入超级块的实际操作。

  所有以上函数都是由VFS在进程上下文中调用。

  索引节点对象

  索引节点对象包含了内核在操作文件或目录时需要的全部信息。如果一个文件系统没有索引节点,那么不管这些相关信息在磁盘上是怎么存放的,文件系统都必须从中提取这些信息。其结构如下:

  


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

  有时一些文件系统并不含有全部的结构体中的信息,此时则随便给这些属性随便赋值即可。

  索引节点操作

  和超级块操作一样,索引节点对象中的inode_operations项也非常重要,因为它描述了VFS用以操作索引节点对象的所有方法——这些方法由文件系统实现。inode_operations结构体如下:



  参考自:《Linux Kernel Development》.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: