Linux__ VFS

VFS就是把各种具体的文件系统的公共部分抽取出来,形成一个抽象层,是系统内核的一部分。它位于用户程序和具体的文件系统之间。它对用户程序提供 了标准的文件系统调用接口,对具体的文件系统,它通过一系列的对不同文件系统公用的函数指针来实际调用具体的文件系统函数,完成实际的各有差异的操作。任 何使用文件系统的程序必须经过这层接口来使用它。通过这样的方式,VFS就对用户屏蔽了底层文件系统的实现细节和差异。

      VFS的实现,其主要思想是引入了一个通用的文件模型(common file model),这个模型的核心是四个对象类型,即超级块对象(superblock object)、索引节点对象(inode object)、文件对象(file object)和目录项对象(dentry object),它们都是内核空间中的数据结构,是VFS的核心,不管各种文件系统的具体格式是什么样的,它们的数据结构在内存中的映象都要和VFS的通用文件模型打交道。

      VFS的基本结构如下:

 

 

其中Buffer Cache是用于底层的文件系统读取磁盘内容的缓冲区,如果需要读取得内容在它里面,就不用读磁盘,用来提高读取速度。而Directory Cache实际上就是Dentry Cache,它是由Dentry节点构成的一个树形结构,由于Dentry node的结构很小,所以这棵树也不大,它可以放在内存的系统核心区,用来提高查找文件的速度。为什么需要它呢?因为Inode的数据结构比较大,所以放 在磁盘上,而文件系统中经常会有大量的查询需求,如果每次都从磁盘上读取Inode进行查找,那么速度将是很慢的,如果把Inode节点构成的查询树放在 内存中,又会因为Inode的较大体积而浪费很多内存,而且很多Inode中保存的信息在查询时并不会使用。所以Dentry就是把Inode中需要的数 据结构提取出来,用来提高查询速度的。每一个打开的文件都有一个Dentry节点,每一个Dentry节点都是与某个Inode一一对应的,在查询结束后 能根据Dentry节点找到对应的Inode节点,然后根据Inode节点中的内容找到文件具体的逻辑块的物理位置。在文件创建,删除和修改 时,Dentry和Inode进行同步的更新。因为Linux支持很大的文件结构,在Directory Cache中,子目录的Dentry节点以散列表的形式排于父目录的Dentry节点之下, 每一个Dentry节点对应一个固定的散列值,使用闭散列方法解决冲突。这样就提高了系统的效率。Dentry和Inode一样都维护一张分配表,不再使 用的Dentry和它对应的Inode会被释放内存空间,然后将它们链入分配表的空闲链表中,以备将来生成新的Dentry节点使用。

 

      在VFS中Inode的结构,是不文件系统公共部分的抽象。对于每一个不同的文件系统,它维护自己的Inode,这些真正意义上的Inode是存在磁盘上 的。当VFS对某个文件系统进行操作时,它传给该文件系统的Inode是由很多具体参数未定的Inode,这些具体的参数在不同文件系统之间是有差异的, 它们的填写应由具体的文件系统负责。

      对于每一个具体的文件系统,在它注册时,都会给它分配一个super block结构存放其重要资料。一个文件系统的super block可以调用这个文件系统中的任何文件,取得这个文件系统中的任意Inode,进而对这个文件做需要的操作,完成Linux对底下文件的控制。VFS直接和super block通信,完成各种操作。super_block结构是所有文件系统所共同使用的一个结构,但是除了共同的部分之外,文件系统之间也有着相当的差异性,为协调差异性,在super_block结构有一个栏位是专门来存放各个文件系统所独自享有的信息。super block里有一个栏位是用来记录一组的函数,是super_operations。这个结构包含了很多函数指针,供VFS调用。这是VFS和文件系统之间的一个接口,经由这层接口,super block可以控制档案系统底下的档案或目录。实际上VFS只是提供一个参数不完整的调用,相关参数的填入和具体实现由该文件系统自己实现。每一个super block都有自己文件系统操纵Inode的函数。

      因为VFS,Linux可以方便的支持新的文件系统。只要该文件系统按照Linux约定的模式重新编写一下该文件系统的基本类型结构,然后通过register_filesystem函数注册一下即可。这个过程实际上是分配super block和初始化它的过程。当不在支持这个文件系统时,只需unregister_filesystem注销该文件系统,内核会把它对应的super block注销,放到空闲super block链表中。

      Linux对文件的操作提供了大量函数。在Linux中,为了便于对文件进行操作,对每一个打开的文件,系统都会给它分配一个唯一的文件ID号,这样当每 个进程想对某个打开的文件进行操作时,只需知道该文件的ID号便可得到相应的文件指针,然后可以进行相应的文件操作。在VFS中,要打开某个文件时,系统 先得到一个空的文件ID号和一个文件信息节点,然后由相应的文件名通过文件的查找得到它的Dentry节点和Inode,建立四者的联系,最后调用具体的 文件系统自身的打开文件函数真正的打开指定的文件。读文件和写文件的函数最终也是调用相应的文件系统的相应函数。在VFS中要关闭一个文件,系统先释放掉 该文件的ID号,然后释放掉其文件信息节点,Dentry节点,Inode,最后调用具体文件系统的关闭函数彻底的关闭该文件。在VFS中还可以测试,改 变,设置文件的访问权限,VFS提供了通用的借口函数,具体实现是由具体的文件系统实现。在VFS中还提供了对文件目录的操作,比如创立,删除,读目录, 获取和改变当前工作目录等等。

      在VFS中提供了两种文件的链接方式。符号链接:符号链接文件有自己的Inode,在该文件的内容中包含了指向的文件的绝对路径,从而可以根据其内容达到 访问源文件的目的。这个源文件可以是不可见的。这种链接可以发生在不同的文件系统之间。硬链接:这些文件没有自己的Inode,它们的Dentry节点指 向同一个Inode,访问时根据Dentry节点找到相应的Inode,然后进行队源文件的访问。索引节点表记录一个文件有多少个链接;只有当最后一个链 接被删除时,该索引节点才最终被释放回空闲表中。这种链接限制在同一个文件系统之内。硬链接与符号链接之间一个主要的差别是:使用硬链接,每个连接都有同 等的地位(也就是说,系统把每个链接都看作是原始文件),并且在文件的最后一个链接被删除之前,实际的数据不会被删除;使用符号链接,当原始文件被删除 时,所有对该文件的符号链接也都被删除,符号链接的文件没有与原始文件相同的地位。

      在VFS中,系统采用不同的文件ID号指向同一个文件信息节点来实现文件的共享。两个不同的进程,如果想共享一个文件,可以让他们的进程打开文件表中某一 项指向相同文件的信息节点,这样两个进程就可以通过不同的文件ID号实现对相同文件的操作。在VFS中提供了两种文件ID号复制的方式:1.选择最小有效 的文件ID号作为新的另一文件ID号;2.用指向定的文件ID号作为新的另一个文件ID号。

      虚拟文件系统提供了很好的通用的借口,使系统屏蔽了不同文件系统对于应用程序的差异。各种具体的操作由具体的文件系统按照各自的方式自己实现。这种想法类 似于面向对象中的多态:系统将不同的文件系统封装起来,向用户提供统一的借口。相同的功能的函数被不同的文件系统重载,完成各自需要的操作。添加新的文件 系统也很容易,提高了Linux系统的可扩展性和兼容性。

posted on 2011-12-01 21:51  espresso0  阅读(387)  评论(0)    收藏  举报